@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.mjs
CHANGED
|
@@ -19,6 +19,12 @@ var __spreadValues = (a, b) => {
|
|
|
19
19
|
return a;
|
|
20
20
|
};
|
|
21
21
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
22
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
23
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
24
|
+
}) : x)(function(x) {
|
|
25
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
26
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
27
|
+
});
|
|
22
28
|
var __objRest = (source, exclude) => {
|
|
23
29
|
var target = {};
|
|
24
30
|
for (var prop in source)
|
|
@@ -59,9 +65,9 @@ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")])
|
|
|
59
65
|
function isRecord(value) {
|
|
60
66
|
return typeof value === "object" && value !== null;
|
|
61
67
|
}
|
|
62
|
-
function resolvePath(obj,
|
|
63
|
-
if (!
|
|
64
|
-
return
|
|
68
|
+
function resolvePath(obj, path2) {
|
|
69
|
+
if (!path2 || !obj) return void 0;
|
|
70
|
+
return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
|
|
65
71
|
if (!isRecord(current) && !Array.isArray(current)) {
|
|
66
72
|
return void 0;
|
|
67
73
|
}
|
|
@@ -171,7 +177,7 @@ var init_PineconeProvider = __esm({
|
|
|
171
177
|
static getHealthChecker() {
|
|
172
178
|
return {
|
|
173
179
|
async check(config) {
|
|
174
|
-
var
|
|
180
|
+
var _a2, _b;
|
|
175
181
|
const opts = config.options || {};
|
|
176
182
|
const indexName = config.indexName;
|
|
177
183
|
const timestamp = Date.now();
|
|
@@ -179,7 +185,7 @@ var init_PineconeProvider = __esm({
|
|
|
179
185
|
const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
|
|
180
186
|
const client = new Pinecone2({ apiKey: opts.apiKey });
|
|
181
187
|
const indexes = await client.listIndexes();
|
|
182
|
-
const indexNames = (_b = (
|
|
188
|
+
const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
183
189
|
if (!indexNames.includes(indexName)) {
|
|
184
190
|
return {
|
|
185
191
|
healthy: false,
|
|
@@ -206,10 +212,10 @@ var init_PineconeProvider = __esm({
|
|
|
206
212
|
};
|
|
207
213
|
}
|
|
208
214
|
async initialize() {
|
|
209
|
-
var
|
|
215
|
+
var _a2, _b;
|
|
210
216
|
this.client = new Pinecone({ apiKey: this.apiKey });
|
|
211
217
|
const indexes = await this.client.listIndexes();
|
|
212
|
-
const names = (_b = (
|
|
218
|
+
const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
213
219
|
if (!names.includes(this.indexName)) {
|
|
214
220
|
throw new Error(
|
|
215
221
|
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
@@ -221,12 +227,12 @@ var init_PineconeProvider = __esm({
|
|
|
221
227
|
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
222
228
|
}
|
|
223
229
|
async upsert(doc, namespace) {
|
|
224
|
-
var
|
|
230
|
+
var _a2;
|
|
225
231
|
await this.index(namespace).upsert({
|
|
226
232
|
records: [{
|
|
227
233
|
id: String(doc.id),
|
|
228
234
|
values: doc.vector,
|
|
229
|
-
metadata: __spreadValues({ content: doc.content }, (
|
|
235
|
+
metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
|
|
230
236
|
}]
|
|
231
237
|
});
|
|
232
238
|
}
|
|
@@ -234,29 +240,29 @@ var init_PineconeProvider = __esm({
|
|
|
234
240
|
const BATCH = 100;
|
|
235
241
|
for (let i = 0; i < docs.length; i += BATCH) {
|
|
236
242
|
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
237
|
-
var
|
|
243
|
+
var _a2;
|
|
238
244
|
return {
|
|
239
245
|
id: String(d.id),
|
|
240
246
|
values: d.vector,
|
|
241
|
-
metadata: __spreadValues({ content: d.content }, (
|
|
247
|
+
metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
|
|
242
248
|
};
|
|
243
249
|
});
|
|
244
250
|
await this.index(namespace).upsert({ records });
|
|
245
251
|
}
|
|
246
252
|
}
|
|
247
253
|
async query(vector, topK, namespace, filter) {
|
|
248
|
-
var
|
|
254
|
+
var _a2;
|
|
249
255
|
const pineconeFilter = this.sanitizeFilter(filter);
|
|
250
256
|
const result = await this.index(namespace).query(__spreadValues({
|
|
251
257
|
vector,
|
|
252
258
|
topK,
|
|
253
259
|
includeMetadata: true
|
|
254
260
|
}, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
|
|
255
|
-
return ((
|
|
256
|
-
var
|
|
261
|
+
return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
|
|
262
|
+
var _a3, _b;
|
|
257
263
|
return {
|
|
258
264
|
id: m.id,
|
|
259
|
-
score: (
|
|
265
|
+
score: (_a3 = m.score) != null ? _a3 : 0,
|
|
260
266
|
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
261
267
|
metadata: m.metadata
|
|
262
268
|
};
|
|
@@ -295,13 +301,13 @@ var init_PostgreSQLProvider = __esm({
|
|
|
295
301
|
init_BaseVectorProvider();
|
|
296
302
|
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
297
303
|
constructor(config) {
|
|
298
|
-
var
|
|
304
|
+
var _a2;
|
|
299
305
|
super(config);
|
|
300
306
|
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
301
307
|
const opts = config.options;
|
|
302
308
|
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
303
309
|
this.connectionString = opts.connectionString;
|
|
304
|
-
this.dimensions = (
|
|
310
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
|
|
305
311
|
}
|
|
306
312
|
static getValidator() {
|
|
307
313
|
return {
|
|
@@ -382,7 +388,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
382
388
|
}
|
|
383
389
|
}
|
|
384
390
|
async upsert(doc, namespace = "") {
|
|
385
|
-
var
|
|
391
|
+
var _a2;
|
|
386
392
|
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
387
393
|
await this.pool.query(
|
|
388
394
|
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
@@ -392,7 +398,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
392
398
|
content = EXCLUDED.content,
|
|
393
399
|
metadata = EXCLUDED.metadata,
|
|
394
400
|
embedding = EXCLUDED.embedding`,
|
|
395
|
-
[doc.id, namespace, doc.content, JSON.stringify((
|
|
401
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
|
|
396
402
|
);
|
|
397
403
|
}
|
|
398
404
|
async batchUpsert(docs, namespace = "") {
|
|
@@ -405,9 +411,9 @@ var init_PostgreSQLProvider = __esm({
|
|
|
405
411
|
const batch = docs.slice(i, i + BATCH_SIZE);
|
|
406
412
|
const values = [];
|
|
407
413
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
408
|
-
var
|
|
414
|
+
var _a2;
|
|
409
415
|
const offset = idx * 5;
|
|
410
|
-
values.push(doc.id, namespace, doc.content, JSON.stringify((
|
|
416
|
+
values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
|
|
411
417
|
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
|
|
412
418
|
}).join(", ");
|
|
413
419
|
const query = `
|
|
@@ -490,8 +496,8 @@ var init_PostgreSQLProvider = __esm({
|
|
|
490
496
|
|
|
491
497
|
// src/utils/synonyms.ts
|
|
492
498
|
function resolveMetadataValue(meta, uiKey) {
|
|
493
|
-
var
|
|
494
|
-
const synonyms = (
|
|
499
|
+
var _a2;
|
|
500
|
+
const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
|
|
495
501
|
const keys = Object.keys(meta);
|
|
496
502
|
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
497
503
|
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
@@ -578,14 +584,14 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
578
584
|
init_synonyms();
|
|
579
585
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
580
586
|
constructor(config) {
|
|
581
|
-
var
|
|
587
|
+
var _a2, _b, _c;
|
|
582
588
|
super(config);
|
|
583
589
|
const opts = config.options || {};
|
|
584
590
|
if (!opts.connectionString) {
|
|
585
591
|
throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
|
|
586
592
|
}
|
|
587
593
|
this.connectionString = opts.connectionString;
|
|
588
|
-
this.dimensions = (
|
|
594
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
|
|
589
595
|
this.tables = [];
|
|
590
596
|
const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
|
|
591
597
|
this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
|
|
@@ -643,11 +649,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
643
649
|
* Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
|
|
644
650
|
*/
|
|
645
651
|
async batchUpsert(docs, namespace = "") {
|
|
646
|
-
var
|
|
652
|
+
var _a2;
|
|
647
653
|
if (docs.length === 0) return;
|
|
648
654
|
const docsByFile = {};
|
|
649
655
|
for (const doc of docs) {
|
|
650
|
-
const fileName = ((
|
|
656
|
+
const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
|
|
651
657
|
if (!docsByFile[fileName]) docsByFile[fileName] = [];
|
|
652
658
|
docsByFile[fileName].push(doc);
|
|
653
659
|
}
|
|
@@ -700,11 +706,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
700
706
|
const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
|
|
701
707
|
const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
|
|
702
708
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
703
|
-
var
|
|
709
|
+
var _a3, _b;
|
|
704
710
|
const offset = idx * (5 + csvHeaders.length);
|
|
705
711
|
values.push(doc.id);
|
|
706
712
|
for (const h of csvHeaders) {
|
|
707
|
-
values.push(String(((
|
|
713
|
+
values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
|
|
708
714
|
}
|
|
709
715
|
values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
|
|
710
716
|
const docPlaceholders = [];
|
|
@@ -743,7 +749,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
743
749
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
744
750
|
*/
|
|
745
751
|
async query(vector, topK, _namespace, _filter) {
|
|
746
|
-
var
|
|
752
|
+
var _a2;
|
|
747
753
|
if (!this.pool) {
|
|
748
754
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
749
755
|
}
|
|
@@ -774,11 +780,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
774
780
|
const filterParams = [];
|
|
775
781
|
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
776
782
|
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
777
|
-
var
|
|
783
|
+
var _a4;
|
|
778
784
|
filterParams.push(String(val));
|
|
779
785
|
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
780
786
|
const paramIdx = baseOffset + filterParams.length;
|
|
781
|
-
const synonyms = (
|
|
787
|
+
const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
|
|
782
788
|
const keysToCheck = [key, ...synonyms];
|
|
783
789
|
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
784
790
|
`metadata->>'${k}'`,
|
|
@@ -847,7 +853,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
847
853
|
}
|
|
848
854
|
const tableResults = [];
|
|
849
855
|
for (const row of result.rows) {
|
|
850
|
-
const
|
|
856
|
+
const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
|
|
851
857
|
delete rest.embedding;
|
|
852
858
|
delete rest.vector_score;
|
|
853
859
|
delete rest.keyword_score;
|
|
@@ -876,10 +882,10 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
876
882
|
}
|
|
877
883
|
allResults.sort((a, b) => b.score - a.score);
|
|
878
884
|
if (allResults.length === 0) return [];
|
|
879
|
-
const bestMatchTable = (
|
|
885
|
+
const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
|
|
880
886
|
const finalSorted = allResults.filter((res) => {
|
|
881
|
-
var
|
|
882
|
-
return ((
|
|
887
|
+
var _a3;
|
|
888
|
+
return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
|
|
883
889
|
});
|
|
884
890
|
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
885
891
|
console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
@@ -1284,14 +1290,14 @@ var init_QdrantProvider = __esm({
|
|
|
1284
1290
|
* Samples points from the collection to discover available payload fields.
|
|
1285
1291
|
*/
|
|
1286
1292
|
async discoverSchema() {
|
|
1287
|
-
var
|
|
1293
|
+
var _a2;
|
|
1288
1294
|
try {
|
|
1289
1295
|
const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
|
|
1290
1296
|
limit: 20,
|
|
1291
1297
|
with_payload: true,
|
|
1292
1298
|
with_vector: false
|
|
1293
1299
|
});
|
|
1294
|
-
const points = ((
|
|
1300
|
+
const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
|
|
1295
1301
|
const keys = /* @__PURE__ */ new Set();
|
|
1296
1302
|
for (const point of points) {
|
|
1297
1303
|
const payload = point.payload || {};
|
|
@@ -1317,12 +1323,12 @@ var init_QdrantProvider = __esm({
|
|
|
1317
1323
|
* Ensures the collection exists. Creates it if missing.
|
|
1318
1324
|
*/
|
|
1319
1325
|
async ensureCollection() {
|
|
1320
|
-
var
|
|
1326
|
+
var _a2;
|
|
1321
1327
|
try {
|
|
1322
1328
|
await this.http.get(`/collections/${this.indexName}`);
|
|
1323
1329
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
1324
1330
|
} catch (err) {
|
|
1325
|
-
if (axios4.isAxiosError(err) && ((
|
|
1331
|
+
if (axios4.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1326
1332
|
const opts = this.config.options;
|
|
1327
1333
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1328
1334
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
@@ -1342,7 +1348,7 @@ var init_QdrantProvider = __esm({
|
|
|
1342
1348
|
* Ensures that a payload field has an index.
|
|
1343
1349
|
*/
|
|
1344
1350
|
async ensureIndex(fieldName, schema = "keyword") {
|
|
1345
|
-
var
|
|
1351
|
+
var _a2;
|
|
1346
1352
|
let fullPath = fieldName;
|
|
1347
1353
|
if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
|
|
1348
1354
|
fullPath = `${this.metadataField}.${fieldName}`;
|
|
@@ -1355,7 +1361,7 @@ var init_QdrantProvider = __esm({
|
|
|
1355
1361
|
console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
|
|
1356
1362
|
} catch (err) {
|
|
1357
1363
|
let status;
|
|
1358
|
-
if (axios4.isAxiosError(err)) status = (
|
|
1364
|
+
if (axios4.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
|
|
1359
1365
|
if (status === 409) return;
|
|
1360
1366
|
console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
|
|
1361
1367
|
}
|
|
@@ -1384,7 +1390,7 @@ var init_QdrantProvider = __esm({
|
|
|
1384
1390
|
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
1385
1391
|
}
|
|
1386
1392
|
async query(vector, topK, namespace, _filter) {
|
|
1387
|
-
var
|
|
1393
|
+
var _a2;
|
|
1388
1394
|
const must = [];
|
|
1389
1395
|
if (namespace) {
|
|
1390
1396
|
must.push({ key: "namespace", match: { value: namespace } });
|
|
@@ -1406,7 +1412,7 @@ var init_QdrantProvider = __esm({
|
|
|
1406
1412
|
limit: topK,
|
|
1407
1413
|
with_payload: true,
|
|
1408
1414
|
params: {
|
|
1409
|
-
hnsw_ef: ((
|
|
1415
|
+
hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
|
|
1410
1416
|
exact: false
|
|
1411
1417
|
},
|
|
1412
1418
|
filter: must.length > 0 ? { must } : void 0
|
|
@@ -1501,13 +1507,13 @@ var init_ChromaDBProvider = __esm({
|
|
|
1501
1507
|
* Get or create the ChromaDB collection.
|
|
1502
1508
|
*/
|
|
1503
1509
|
async initialize() {
|
|
1504
|
-
var
|
|
1510
|
+
var _a2;
|
|
1505
1511
|
try {
|
|
1506
1512
|
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1507
1513
|
this.collectionId = data.id;
|
|
1508
1514
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1509
1515
|
} catch (err) {
|
|
1510
|
-
if (axios5.isAxiosError(err) && ((
|
|
1516
|
+
if (axios5.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1511
1517
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1512
1518
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1513
1519
|
name: this.indexName
|
|
@@ -1728,7 +1734,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1728
1734
|
await this.http.post("/v1/batch/objects", payload);
|
|
1729
1735
|
}
|
|
1730
1736
|
async query(vector, topK, namespace, _filter) {
|
|
1731
|
-
var
|
|
1737
|
+
var _a2, _b;
|
|
1732
1738
|
const queryText = _filter == null ? void 0 : _filter.queryText;
|
|
1733
1739
|
const sanitizedFilter = this.sanitizeFilter(_filter);
|
|
1734
1740
|
const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
|
|
@@ -1754,7 +1760,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1754
1760
|
`
|
|
1755
1761
|
};
|
|
1756
1762
|
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1757
|
-
const results = ((_b = (
|
|
1763
|
+
const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1758
1764
|
return results.map((res) => ({
|
|
1759
1765
|
id: res["_additional"].id,
|
|
1760
1766
|
score: 1 - res["_additional"].distance,
|
|
@@ -1807,10 +1813,10 @@ var init_WeaviateProvider = __esm({
|
|
|
1807
1813
|
return `{ operator: And, operands: [${operands.join(", ")}] }`;
|
|
1808
1814
|
}
|
|
1809
1815
|
weaviateOperand(key, value) {
|
|
1810
|
-
const
|
|
1811
|
-
if (typeof value === "number") return `{ ${
|
|
1812
|
-
if (typeof value === "boolean") return `{ ${
|
|
1813
|
-
return `{ ${
|
|
1816
|
+
const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
|
|
1817
|
+
if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
|
|
1818
|
+
if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
|
|
1819
|
+
return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
|
|
1814
1820
|
}
|
|
1815
1821
|
};
|
|
1816
1822
|
}
|
|
@@ -1837,21 +1843,21 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1837
1843
|
}
|
|
1838
1844
|
}
|
|
1839
1845
|
async initialize() {
|
|
1840
|
-
var
|
|
1846
|
+
var _a2;
|
|
1841
1847
|
this.http = axios8.create({
|
|
1842
1848
|
baseURL: this.opts.baseUrl,
|
|
1843
1849
|
headers: __spreadValues({
|
|
1844
1850
|
"Content-Type": "application/json"
|
|
1845
1851
|
}, this.opts.headers),
|
|
1846
|
-
timeout: (
|
|
1852
|
+
timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
|
|
1847
1853
|
});
|
|
1848
1854
|
if (!await this.ping()) {
|
|
1849
1855
|
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1850
1856
|
}
|
|
1851
1857
|
}
|
|
1852
1858
|
async upsert(doc, namespace) {
|
|
1853
|
-
var
|
|
1854
|
-
const endpoint = (
|
|
1859
|
+
var _a2, _b, _c;
|
|
1860
|
+
const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
|
|
1855
1861
|
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1856
1862
|
id: "{{id}}",
|
|
1857
1863
|
vector: "{{vector}}",
|
|
@@ -1884,8 +1890,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1884
1890
|
}
|
|
1885
1891
|
}
|
|
1886
1892
|
async query(vector, topK, namespace, filter) {
|
|
1887
|
-
var
|
|
1888
|
-
const endpoint = (
|
|
1893
|
+
var _a2, _b;
|
|
1894
|
+
const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
|
|
1889
1895
|
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1890
1896
|
vector: "{{vector}}",
|
|
1891
1897
|
limit: "{{topK}}",
|
|
@@ -1911,12 +1917,12 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1911
1917
|
);
|
|
1912
1918
|
}
|
|
1913
1919
|
return results.map((item) => {
|
|
1914
|
-
var
|
|
1920
|
+
var _a3, _b2, _c, _d, _e, _f, _g2;
|
|
1915
1921
|
return {
|
|
1916
|
-
id: item[(
|
|
1922
|
+
id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
|
|
1917
1923
|
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1918
1924
|
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1919
|
-
metadata: (
|
|
1925
|
+
metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
|
|
1920
1926
|
};
|
|
1921
1927
|
});
|
|
1922
1928
|
} catch (error) {
|
|
@@ -1926,8 +1932,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1926
1932
|
}
|
|
1927
1933
|
}
|
|
1928
1934
|
async delete(id, namespace) {
|
|
1929
|
-
var
|
|
1930
|
-
const endpoint = (
|
|
1935
|
+
var _a2, _b;
|
|
1936
|
+
const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
|
|
1931
1937
|
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1932
1938
|
id: "{{id}}",
|
|
1933
1939
|
namespace: "{{namespace}}"
|
|
@@ -1945,8 +1951,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1945
1951
|
}
|
|
1946
1952
|
}
|
|
1947
1953
|
async deleteNamespace(namespace) {
|
|
1948
|
-
var
|
|
1949
|
-
const endpoint = (
|
|
1954
|
+
var _a2;
|
|
1955
|
+
const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
|
|
1950
1956
|
try {
|
|
1951
1957
|
await this.http.post(endpoint, { namespace });
|
|
1952
1958
|
} catch (error) {
|
|
@@ -1956,9 +1962,9 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1956
1962
|
}
|
|
1957
1963
|
}
|
|
1958
1964
|
async ping() {
|
|
1959
|
-
var
|
|
1965
|
+
var _a2;
|
|
1960
1966
|
try {
|
|
1961
|
-
const endpoint = (
|
|
1967
|
+
const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
|
|
1962
1968
|
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
1963
1969
|
return response.status >= 200 && response.status < 300;
|
|
1964
1970
|
} catch (e) {
|
|
@@ -2072,6 +2078,8 @@ var LLM_PROVIDERS = [
|
|
|
2072
2078
|
"anthropic",
|
|
2073
2079
|
"ollama",
|
|
2074
2080
|
"gemini",
|
|
2081
|
+
"groq",
|
|
2082
|
+
"qwen",
|
|
2075
2083
|
"rest",
|
|
2076
2084
|
"universal_rest",
|
|
2077
2085
|
"custom"
|
|
@@ -2080,6 +2088,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2080
2088
|
"openai",
|
|
2081
2089
|
"ollama",
|
|
2082
2090
|
"gemini",
|
|
2091
|
+
"qwen",
|
|
2083
2092
|
"rest",
|
|
2084
2093
|
"universal_rest",
|
|
2085
2094
|
"custom"
|
|
@@ -2088,6 +2097,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2088
2097
|
"openai",
|
|
2089
2098
|
"ollama",
|
|
2090
2099
|
"gemini",
|
|
2100
|
+
"qwen",
|
|
2091
2101
|
"rest",
|
|
2092
2102
|
"universal_rest"
|
|
2093
2103
|
];
|
|
@@ -2095,8 +2105,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2095
2105
|
|
|
2096
2106
|
// src/config/serverConfig.ts
|
|
2097
2107
|
function readString(env, name) {
|
|
2098
|
-
var
|
|
2099
|
-
const value = (
|
|
2108
|
+
var _a2;
|
|
2109
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2100
2110
|
return value ? value : void 0;
|
|
2101
2111
|
}
|
|
2102
2112
|
function readNumber(env, name, fallback) {
|
|
@@ -2109,23 +2119,23 @@ function readNumber(env, name, fallback) {
|
|
|
2109
2119
|
return parsed;
|
|
2110
2120
|
}
|
|
2111
2121
|
function readEnum(env, name, fallback, allowed) {
|
|
2112
|
-
var
|
|
2113
|
-
const value = (
|
|
2122
|
+
var _a2;
|
|
2123
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2114
2124
|
if (allowed.includes(value)) {
|
|
2115
2125
|
return value;
|
|
2116
2126
|
}
|
|
2117
2127
|
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
2118
2128
|
}
|
|
2119
2129
|
function getEnvConfig(env = process.env, base) {
|
|
2120
|
-
var
|
|
2121
|
-
const projectId = (_c = (_b = (
|
|
2130
|
+
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;
|
|
2131
|
+
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__";
|
|
2122
2132
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2123
2133
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2124
2134
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2125
2135
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2126
2136
|
const vectorDbOptions = {};
|
|
2127
2137
|
if (vectorProvider === "pinecone") {
|
|
2128
|
-
vectorDbOptions.apiKey = (
|
|
2138
|
+
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 : "";
|
|
2129
2139
|
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;
|
|
2130
2140
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2131
2141
|
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 : "";
|
|
@@ -2187,17 +2197,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2187
2197
|
rest: "default",
|
|
2188
2198
|
custom: "default"
|
|
2189
2199
|
};
|
|
2190
|
-
return __spreadValues({
|
|
2200
|
+
return __spreadProps(__spreadValues({
|
|
2191
2201
|
projectId,
|
|
2202
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2192
2203
|
vectorDb: {
|
|
2193
2204
|
provider: vectorProvider,
|
|
2194
|
-
indexName: (
|
|
2205
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2195
2206
|
options: vectorDbOptions
|
|
2196
2207
|
},
|
|
2197
2208
|
llm: {
|
|
2198
2209
|
provider: llmProvider,
|
|
2199
|
-
model: (
|
|
2200
|
-
apiKey: (
|
|
2210
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2211
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2201
2212
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2202
2213
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2203
2214
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2210,7 +2221,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2210
2221
|
},
|
|
2211
2222
|
embedding: {
|
|
2212
2223
|
provider: embeddingProvider,
|
|
2213
|
-
model: (
|
|
2224
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2214
2225
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2215
2226
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2216
2227
|
dimensions: embeddingDimensions,
|
|
@@ -2221,30 +2232,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2221
2232
|
}
|
|
2222
2233
|
},
|
|
2223
2234
|
ui: {
|
|
2224
|
-
title: (
|
|
2225
|
-
subtitle: (
|
|
2226
|
-
primaryColor: (
|
|
2227
|
-
accentColor: (
|
|
2228
|
-
logoUrl: (
|
|
2229
|
-
placeholder: (
|
|
2230
|
-
showSources: ((
|
|
2231
|
-
welcomeMessage: (
|
|
2232
|
-
visualStyle: (
|
|
2233
|
-
borderRadius: (
|
|
2234
|
-
allowUpload: ((
|
|
2235
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2236
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2237
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2238
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2239
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2240
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2241
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2242
|
+
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.",
|
|
2243
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2244
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2245
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2235
2246
|
},
|
|
2236
2247
|
rag: {
|
|
2237
2248
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2238
2249
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2239
2250
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2240
2251
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2241
|
-
filterableFields: (
|
|
2252
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2242
2253
|
// Query pipeline toggles — read from .env.local
|
|
2243
2254
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2244
2255
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2245
2256
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2246
|
-
architecture: (
|
|
2247
|
-
chunkingStrategy: (
|
|
2257
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2258
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2248
2259
|
uiMapping: (() => {
|
|
2249
2260
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2250
2261
|
if (!raw) return void 0;
|
|
@@ -2254,6 +2265,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2254
2265
|
return void 0;
|
|
2255
2266
|
}
|
|
2256
2267
|
})()
|
|
2268
|
+
},
|
|
2269
|
+
telemetry: {
|
|
2270
|
+
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,
|
|
2271
|
+
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"
|
|
2257
2272
|
}
|
|
2258
2273
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2259
2274
|
graphDb: {
|
|
@@ -2264,7 +2279,19 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2264
2279
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2265
2280
|
}
|
|
2266
2281
|
}
|
|
2267
|
-
} : {})
|
|
2282
|
+
} : {}), {
|
|
2283
|
+
mcpServers: (() => {
|
|
2284
|
+
var _a3;
|
|
2285
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2286
|
+
if (!raw) return void 0;
|
|
2287
|
+
try {
|
|
2288
|
+
return JSON.parse(raw);
|
|
2289
|
+
} catch (e) {
|
|
2290
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2291
|
+
return void 0;
|
|
2292
|
+
}
|
|
2293
|
+
})()
|
|
2294
|
+
});
|
|
2268
2295
|
}
|
|
2269
2296
|
|
|
2270
2297
|
// src/core/ConfigResolver.ts
|
|
@@ -2290,7 +2317,8 @@ var ConfigResolver = class {
|
|
|
2290
2317
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2291
2318
|
}) : envConfig.embedding,
|
|
2292
2319
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2293
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2320
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2321
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2294
2322
|
});
|
|
2295
2323
|
}
|
|
2296
2324
|
/**
|
|
@@ -2299,10 +2327,10 @@ var ConfigResolver = class {
|
|
|
2299
2327
|
* fallback behavior.
|
|
2300
2328
|
*/
|
|
2301
2329
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2302
|
-
var
|
|
2330
|
+
var _a2;
|
|
2303
2331
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2304
2332
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2305
|
-
vectorDb: (
|
|
2333
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2306
2334
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2307
2335
|
});
|
|
2308
2336
|
return this.resolve(normalized, env);
|
|
@@ -2322,28 +2350,52 @@ var ConfigResolver = class {
|
|
|
2322
2350
|
}
|
|
2323
2351
|
}
|
|
2324
2352
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2325
|
-
var
|
|
2353
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2326
2354
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2327
2355
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2328
2356
|
if (retrieval) {
|
|
2329
|
-
normalized.topK = (
|
|
2357
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2330
2358
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2331
2359
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2332
2360
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
2333
|
-
if (retrieval.strategy === "agentic") normalized.architecture = "
|
|
2334
|
-
if (retrieval.strategy === "contextual-compression")
|
|
2361
|
+
if (retrieval.strategy === "agentic") normalized.architecture = "multi-agent";
|
|
2362
|
+
if (retrieval.strategy === "contextual-compression") {
|
|
2363
|
+
normalized.useReranking = true;
|
|
2364
|
+
normalized.architecture = (_e = normalized.architecture) != null ? _e : "retrieve-and-rerank";
|
|
2365
|
+
}
|
|
2335
2366
|
}
|
|
2336
2367
|
if (workflow == null ? void 0 : workflow.type) {
|
|
2337
2368
|
const type = workflow.type;
|
|
2338
|
-
if (type === "
|
|
2339
|
-
|
|
2340
|
-
|
|
2369
|
+
if (type === "naive-rag") {
|
|
2370
|
+
normalized.architecture = "naive";
|
|
2371
|
+
normalized.useReranking = false;
|
|
2372
|
+
normalized.useGraphRetrieval = false;
|
|
2373
|
+
} else if (type === "retrieve-and-rerank") {
|
|
2374
|
+
normalized.architecture = "retrieve-and-rerank";
|
|
2375
|
+
normalized.useReranking = true;
|
|
2376
|
+
} else if (type === "multimodal-rag") {
|
|
2377
|
+
normalized.architecture = "multimodal";
|
|
2378
|
+
} else if (type === "graph-rag") {
|
|
2341
2379
|
normalized.architecture = "graph";
|
|
2342
2380
|
normalized.useGraphRetrieval = true;
|
|
2381
|
+
} else if (type === "hybrid-rag") {
|
|
2382
|
+
normalized.architecture = "hybrid";
|
|
2383
|
+
} else if (type === "agentic-router") {
|
|
2384
|
+
normalized.architecture = "agentic-router";
|
|
2385
|
+
} else if (type === "multi-agent-rag" || type === "multi-agent" || type === "agentic" || type === "agentic-rag") {
|
|
2386
|
+
normalized.architecture = "multi-agent";
|
|
2343
2387
|
} else if (type === "simple-rag" || type === "rag") {
|
|
2344
|
-
normalized.architecture = (
|
|
2388
|
+
normalized.architecture = (_f = normalized.architecture) != null ? _f : "naive";
|
|
2345
2389
|
}
|
|
2346
2390
|
}
|
|
2391
|
+
if (normalized.architecture === "retrieve-and-rerank") {
|
|
2392
|
+
normalized.useReranking = true;
|
|
2393
|
+
} else if (normalized.architecture === "graph") {
|
|
2394
|
+
normalized.useGraphRetrieval = true;
|
|
2395
|
+
} else if (normalized.architecture === "naive") {
|
|
2396
|
+
normalized.useReranking = false;
|
|
2397
|
+
normalized.useGraphRetrieval = false;
|
|
2398
|
+
}
|
|
2347
2399
|
return normalized;
|
|
2348
2400
|
}
|
|
2349
2401
|
};
|
|
@@ -2408,8 +2460,8 @@ var OpenAIProvider = class {
|
|
|
2408
2460
|
const apiKey = config.apiKey;
|
|
2409
2461
|
const modelName = config.model;
|
|
2410
2462
|
try {
|
|
2411
|
-
const
|
|
2412
|
-
const client = new
|
|
2463
|
+
const OpenAI4 = await import("openai");
|
|
2464
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2413
2465
|
const models = await client.models.list();
|
|
2414
2466
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2415
2467
|
return {
|
|
@@ -2430,8 +2482,8 @@ var OpenAIProvider = class {
|
|
|
2430
2482
|
};
|
|
2431
2483
|
}
|
|
2432
2484
|
async chat(messages, context, options) {
|
|
2433
|
-
var
|
|
2434
|
-
const basePrompt = (_b = (
|
|
2485
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2486
|
+
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.";
|
|
2435
2487
|
const systemMessage = {
|
|
2436
2488
|
role: "system",
|
|
2437
2489
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2450,12 +2502,12 @@ var OpenAIProvider = class {
|
|
|
2450
2502
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2451
2503
|
stop: options == null ? void 0 : options.stop
|
|
2452
2504
|
});
|
|
2453
|
-
return (_i = (_h = (
|
|
2505
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2454
2506
|
}
|
|
2455
2507
|
chatStream(messages, context, options) {
|
|
2456
2508
|
return __asyncGenerator(this, null, function* () {
|
|
2457
|
-
var
|
|
2458
|
-
const basePrompt = (_b = (
|
|
2509
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2510
|
+
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.";
|
|
2459
2511
|
const systemMessage = {
|
|
2460
2512
|
role: "system",
|
|
2461
2513
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2481,7 +2533,7 @@ var OpenAIProvider = class {
|
|
|
2481
2533
|
try {
|
|
2482
2534
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2483
2535
|
const chunk = temp.value;
|
|
2484
|
-
const content = ((_h = (
|
|
2536
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2485
2537
|
if (content) yield content;
|
|
2486
2538
|
}
|
|
2487
2539
|
} catch (temp) {
|
|
@@ -2501,8 +2553,8 @@ var OpenAIProvider = class {
|
|
|
2501
2553
|
return results[0];
|
|
2502
2554
|
}
|
|
2503
2555
|
async batchEmbed(texts, options) {
|
|
2504
|
-
var
|
|
2505
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2556
|
+
var _a2, _b, _c, _d, _e;
|
|
2557
|
+
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";
|
|
2506
2558
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2507
2559
|
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI({ apiKey }) : this.client;
|
|
2508
2560
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2579,8 +2631,8 @@ var AnthropicProvider = class {
|
|
|
2579
2631
|
};
|
|
2580
2632
|
}
|
|
2581
2633
|
async chat(messages, context, options) {
|
|
2582
|
-
var
|
|
2583
|
-
const basePrompt = (_b = (
|
|
2634
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2635
|
+
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.";
|
|
2584
2636
|
const system = buildSystemContent(basePrompt, context);
|
|
2585
2637
|
const anthropicMessages = messages.map((m) => ({
|
|
2586
2638
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2591,7 +2643,7 @@ var AnthropicProvider = class {
|
|
|
2591
2643
|
const extraParams = {};
|
|
2592
2644
|
if (isThinkingEnabled && isClaude37) {
|
|
2593
2645
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2594
|
-
const maxTokens = (
|
|
2646
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2595
2647
|
const budget = Math.min(
|
|
2596
2648
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2597
2649
|
maxTokens - 1
|
|
@@ -2618,8 +2670,8 @@ var AnthropicProvider = class {
|
|
|
2618
2670
|
}
|
|
2619
2671
|
chatStream(messages, context, options) {
|
|
2620
2672
|
return __asyncGenerator(this, null, function* () {
|
|
2621
|
-
var
|
|
2622
|
-
const basePrompt = (_b = (
|
|
2673
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2674
|
+
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.";
|
|
2623
2675
|
const system = buildSystemContent(basePrompt, context);
|
|
2624
2676
|
const anthropicMessages = messages.map((m) => ({
|
|
2625
2677
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2630,7 +2682,7 @@ var AnthropicProvider = class {
|
|
|
2630
2682
|
const extraParams = {};
|
|
2631
2683
|
if (isThinkingEnabled && isClaude37) {
|
|
2632
2684
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2633
|
-
const maxTokens = (
|
|
2685
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2634
2686
|
const budget = Math.min(
|
|
2635
2687
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2636
2688
|
maxTokens - 1
|
|
@@ -2703,8 +2755,8 @@ var AnthropicProvider = class {
|
|
|
2703
2755
|
import axios from "axios";
|
|
2704
2756
|
var OllamaProvider = class {
|
|
2705
2757
|
constructor(llmConfig, embeddingConfig) {
|
|
2706
|
-
var
|
|
2707
|
-
const baseURL = (
|
|
2758
|
+
var _a2, _b;
|
|
2759
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2708
2760
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2709
2761
|
this.http = axios.create({ baseURL, timeout });
|
|
2710
2762
|
this.llmConfig = llmConfig;
|
|
@@ -2762,8 +2814,8 @@ var OllamaProvider = class {
|
|
|
2762
2814
|
};
|
|
2763
2815
|
}
|
|
2764
2816
|
async chat(messages, context, options) {
|
|
2765
|
-
var
|
|
2766
|
-
const basePrompt = (_b = (
|
|
2817
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2818
|
+
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.";
|
|
2767
2819
|
const system = buildSystemContent(basePrompt, context);
|
|
2768
2820
|
const { data } = await this.http.post("/api/chat", {
|
|
2769
2821
|
model: this.llmConfig.model,
|
|
@@ -2781,8 +2833,8 @@ var OllamaProvider = class {
|
|
|
2781
2833
|
}
|
|
2782
2834
|
chatStream(messages, context, options) {
|
|
2783
2835
|
return __asyncGenerator(this, null, function* () {
|
|
2784
|
-
var
|
|
2785
|
-
const basePrompt = (_b = (
|
|
2836
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2837
|
+
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.";
|
|
2786
2838
|
const system = buildSystemContent(basePrompt, context);
|
|
2787
2839
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2788
2840
|
model: this.llmConfig.model,
|
|
@@ -2811,7 +2863,7 @@ var OllamaProvider = class {
|
|
|
2811
2863
|
if (!line.trim()) continue;
|
|
2812
2864
|
try {
|
|
2813
2865
|
const json = JSON.parse(line);
|
|
2814
|
-
if ((
|
|
2866
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2815
2867
|
yield json.message.content;
|
|
2816
2868
|
}
|
|
2817
2869
|
if (json.done) return;
|
|
@@ -2840,10 +2892,10 @@ var OllamaProvider = class {
|
|
|
2840
2892
|
});
|
|
2841
2893
|
}
|
|
2842
2894
|
async embed(text, options) {
|
|
2843
|
-
var
|
|
2844
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2895
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2896
|
+
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";
|
|
2845
2897
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2846
|
-
const client = baseURL !== ((
|
|
2898
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? axios.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2847
2899
|
let prompt = text;
|
|
2848
2900
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2849
2901
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -2942,9 +2994,9 @@ var GeminiProvider = class {
|
|
|
2942
2994
|
static getHealthChecker() {
|
|
2943
2995
|
return {
|
|
2944
2996
|
async check(config) {
|
|
2945
|
-
var
|
|
2997
|
+
var _a2, _b;
|
|
2946
2998
|
const timestamp = Date.now();
|
|
2947
|
-
const apiKey = (_b = (
|
|
2999
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
2948
3000
|
const modelName = sanitizeModel(config.model);
|
|
2949
3001
|
try {
|
|
2950
3002
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -2974,16 +3026,16 @@ var GeminiProvider = class {
|
|
|
2974
3026
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
2975
3027
|
* API key differs from the LLM API key. */
|
|
2976
3028
|
get embeddingClient() {
|
|
2977
|
-
var
|
|
2978
|
-
if (((
|
|
3029
|
+
var _a2;
|
|
3030
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
2979
3031
|
return buildClient(this.embeddingConfig.apiKey);
|
|
2980
3032
|
}
|
|
2981
3033
|
return this.client;
|
|
2982
3034
|
}
|
|
2983
3035
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
2984
3036
|
resolveEmbeddingModel(optionsModel) {
|
|
2985
|
-
var
|
|
2986
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3037
|
+
var _a2, _b;
|
|
3038
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
2987
3039
|
}
|
|
2988
3040
|
/**
|
|
2989
3041
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3003,8 +3055,8 @@ var GeminiProvider = class {
|
|
|
3003
3055
|
// ILLMProvider — chat
|
|
3004
3056
|
// -------------------------------------------------------------------------
|
|
3005
3057
|
async chat(messages, context, options) {
|
|
3006
|
-
var
|
|
3007
|
-
const basePrompt = (_b = (
|
|
3058
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3059
|
+
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.";
|
|
3008
3060
|
const model = this.client.getGenerativeModel({
|
|
3009
3061
|
model: this.llmConfig.model,
|
|
3010
3062
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3021,8 +3073,8 @@ var GeminiProvider = class {
|
|
|
3021
3073
|
}
|
|
3022
3074
|
chatStream(messages, context, options) {
|
|
3023
3075
|
return __asyncGenerator(this, null, function* () {
|
|
3024
|
-
var
|
|
3025
|
-
const basePrompt = (_b = (
|
|
3076
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3077
|
+
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.";
|
|
3026
3078
|
const model = this.client.getGenerativeModel({
|
|
3027
3079
|
model: this.llmConfig.model,
|
|
3028
3080
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3057,11 +3109,11 @@ var GeminiProvider = class {
|
|
|
3057
3109
|
// ILLMProvider — embeddings
|
|
3058
3110
|
// -------------------------------------------------------------------------
|
|
3059
3111
|
async embed(text, options) {
|
|
3060
|
-
var
|
|
3112
|
+
var _a2, _b;
|
|
3061
3113
|
const content = applyPrefix(
|
|
3062
3114
|
text,
|
|
3063
3115
|
options == null ? void 0 : options.taskType,
|
|
3064
|
-
(
|
|
3116
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3065
3117
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3066
3118
|
);
|
|
3067
3119
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3078,7 +3130,7 @@ var GeminiProvider = class {
|
|
|
3078
3130
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3079
3131
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3080
3132
|
const requests = texts.map((text) => {
|
|
3081
|
-
var
|
|
3133
|
+
var _a2, _b;
|
|
3082
3134
|
return {
|
|
3083
3135
|
content: {
|
|
3084
3136
|
role: "user",
|
|
@@ -3086,7 +3138,7 @@ var GeminiProvider = class {
|
|
|
3086
3138
|
text: applyPrefix(
|
|
3087
3139
|
text,
|
|
3088
3140
|
options == null ? void 0 : options.taskType,
|
|
3089
|
-
(
|
|
3141
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3090
3142
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3091
3143
|
)
|
|
3092
3144
|
}]
|
|
@@ -3103,8 +3155,8 @@ var GeminiProvider = class {
|
|
|
3103
3155
|
throw err;
|
|
3104
3156
|
});
|
|
3105
3157
|
return response.embeddings.map((e) => {
|
|
3106
|
-
var
|
|
3107
|
-
return (
|
|
3158
|
+
var _a2;
|
|
3159
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3108
3160
|
});
|
|
3109
3161
|
}
|
|
3110
3162
|
// -------------------------------------------------------------------------
|
|
@@ -3124,190 +3176,509 @@ var GeminiProvider = class {
|
|
|
3124
3176
|
}
|
|
3125
3177
|
};
|
|
3126
3178
|
|
|
3127
|
-
// src/llm/providers/
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3138
|
-
};
|
|
3139
|
-
var LLM_PROFILES = {
|
|
3140
|
-
"openai-compatible": OPENAI_BASE,
|
|
3141
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3142
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3143
|
-
}),
|
|
3144
|
-
"anthropic-claude": {
|
|
3145
|
-
chatPath: "/v1/messages",
|
|
3146
|
-
responseExtractPath: "content[0].text",
|
|
3147
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
3148
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3149
|
-
},
|
|
3150
|
-
"google-gemini": {
|
|
3151
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3152
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3153
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3154
|
-
},
|
|
3155
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3156
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3157
|
-
}),
|
|
3158
|
-
"ollama-standard": {
|
|
3159
|
-
chatPath: "/api/chat",
|
|
3160
|
-
embedPath: "/api/embeddings",
|
|
3161
|
-
responseExtractPath: "message.content",
|
|
3162
|
-
embedExtractPath: "embedding",
|
|
3163
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3164
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3165
|
-
}
|
|
3166
|
-
};
|
|
3167
|
-
|
|
3168
|
-
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3169
|
-
var UniversalLLMAdapter = class {
|
|
3170
|
-
constructor(config) {
|
|
3171
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3172
|
-
this.model = config.model;
|
|
3173
|
-
const llmConfig = config;
|
|
3174
|
-
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
3175
|
-
let profile = {};
|
|
3176
|
-
if (typeof options.profile === "string") {
|
|
3177
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
3178
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3179
|
-
profile = options.profile;
|
|
3180
|
-
}
|
|
3181
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3182
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3183
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3184
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3185
|
-
this.apiKey = config.apiKey;
|
|
3186
|
-
this.baseUrl = (_g = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g : "";
|
|
3187
|
-
if (!this.baseUrl) {
|
|
3188
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3189
|
-
}
|
|
3190
|
-
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3191
|
-
"Content-Type": "application/json"
|
|
3192
|
-
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3193
|
-
this.http = axios2.create({
|
|
3194
|
-
baseURL: this.baseUrl,
|
|
3195
|
-
headers: this.resolvedHeaders,
|
|
3196
|
-
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3179
|
+
// src/llm/providers/GroqProvider.ts
|
|
3180
|
+
import OpenAI2 from "openai";
|
|
3181
|
+
var GroqProvider = class {
|
|
3182
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3183
|
+
void embeddingConfig;
|
|
3184
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3185
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3186
|
+
this.client = new OpenAI2({
|
|
3187
|
+
apiKey,
|
|
3188
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3197
3189
|
});
|
|
3190
|
+
this.llmConfig = llmConfig;
|
|
3198
3191
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3192
|
+
static getValidator() {
|
|
3193
|
+
return {
|
|
3194
|
+
validate(config) {
|
|
3195
|
+
const errors = [];
|
|
3196
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3197
|
+
errors.push({
|
|
3198
|
+
field: "llm.apiKey",
|
|
3199
|
+
message: "Groq API key is required",
|
|
3200
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3201
|
+
severity: "error"
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
if (!config.model) {
|
|
3205
|
+
errors.push({
|
|
3206
|
+
field: "llm.model",
|
|
3207
|
+
message: "Groq model name is required",
|
|
3208
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3209
|
+
severity: "error"
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
return errors;
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
}
|
|
3216
|
+
static getHealthChecker() {
|
|
3217
|
+
return {
|
|
3218
|
+
async check(config) {
|
|
3219
|
+
const timestamp = Date.now();
|
|
3220
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3221
|
+
const modelName = config.model;
|
|
3222
|
+
try {
|
|
3223
|
+
const OpenAI4 = await import("openai");
|
|
3224
|
+
const client = new OpenAI4.default({
|
|
3225
|
+
apiKey,
|
|
3226
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3227
|
+
});
|
|
3228
|
+
const models = await client.models.list();
|
|
3229
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3230
|
+
return {
|
|
3231
|
+
healthy: true,
|
|
3232
|
+
provider: "groq",
|
|
3233
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3234
|
+
timestamp
|
|
3235
|
+
};
|
|
3236
|
+
} catch (error) {
|
|
3237
|
+
return {
|
|
3238
|
+
healthy: false,
|
|
3239
|
+
provider: "groq",
|
|
3240
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3241
|
+
timestamp
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
};
|
|
3246
|
+
}
|
|
3247
|
+
async chat(messages, context, options) {
|
|
3248
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3249
|
+
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.";
|
|
3250
|
+
const systemMessage = {
|
|
3251
|
+
role: "system",
|
|
3252
|
+
content: buildSystemContent(basePrompt, context)
|
|
3253
|
+
};
|
|
3202
3254
|
const formattedMessages = [
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3255
|
+
systemMessage,
|
|
3256
|
+
...messages.map((m) => ({
|
|
3257
|
+
role: m.role,
|
|
3258
|
+
content: m.content
|
|
3259
|
+
}))
|
|
3208
3260
|
];
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
} else {
|
|
3218
|
-
payload = {
|
|
3219
|
-
model: this.model,
|
|
3220
|
-
messages: formattedMessages,
|
|
3221
|
-
max_tokens: this.maxTokens,
|
|
3222
|
-
temperature: this.temperature
|
|
3223
|
-
};
|
|
3224
|
-
}
|
|
3225
|
-
const { data } = await this.http.post(path, payload);
|
|
3226
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3227
|
-
const result = resolvePath(data, extractPath);
|
|
3228
|
-
if (result === void 0) {
|
|
3229
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3230
|
-
}
|
|
3231
|
-
return String(result);
|
|
3261
|
+
const completion = await this.client.chat.completions.create({
|
|
3262
|
+
model: this.llmConfig.model,
|
|
3263
|
+
messages: formattedMessages,
|
|
3264
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3265
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3266
|
+
stop: options == null ? void 0 : options.stop
|
|
3267
|
+
});
|
|
3268
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3232
3269
|
}
|
|
3233
|
-
|
|
3234
|
-
* Streaming chat using native fetch + ReadableStream.
|
|
3235
|
-
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3236
|
-
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3237
|
-
*/
|
|
3238
|
-
chatStream(messages, context) {
|
|
3270
|
+
chatStream(messages, context, options) {
|
|
3239
3271
|
return __asyncGenerator(this, null, function* () {
|
|
3240
|
-
var
|
|
3241
|
-
const
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3272
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3273
|
+
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.";
|
|
3274
|
+
const systemMessage = {
|
|
3275
|
+
role: "system",
|
|
3276
|
+
content: buildSystemContent(basePrompt, context)
|
|
3277
|
+
};
|
|
3244
3278
|
const formattedMessages = [
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3279
|
+
systemMessage,
|
|
3280
|
+
...messages.map((m) => ({
|
|
3281
|
+
role: m.role,
|
|
3282
|
+
content: m.content
|
|
3283
|
+
}))
|
|
3250
3284
|
];
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
});
|
|
3259
|
-
if (typeof payload === "object" && payload !== null) {
|
|
3260
|
-
payload.stream = true;
|
|
3261
|
-
}
|
|
3262
|
-
} else {
|
|
3263
|
-
payload = {
|
|
3264
|
-
model: this.model,
|
|
3265
|
-
messages: formattedMessages,
|
|
3266
|
-
max_tokens: this.maxTokens,
|
|
3267
|
-
temperature: this.temperature,
|
|
3268
|
-
stream: true
|
|
3269
|
-
};
|
|
3270
|
-
}
|
|
3271
|
-
const response = yield new __await(fetch(url, {
|
|
3272
|
-
method: "POST",
|
|
3273
|
-
headers: this.resolvedHeaders,
|
|
3274
|
-
body: JSON.stringify(payload)
|
|
3285
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3286
|
+
model: this.llmConfig.model,
|
|
3287
|
+
messages: formattedMessages,
|
|
3288
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3289
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3290
|
+
stop: options == null ? void 0 : options.stop,
|
|
3291
|
+
stream: true
|
|
3275
3292
|
}));
|
|
3276
|
-
if (!
|
|
3277
|
-
|
|
3278
|
-
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3279
|
-
}
|
|
3280
|
-
if (!response.body) {
|
|
3281
|
-
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3293
|
+
if (!stream) {
|
|
3294
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3282
3295
|
}
|
|
3283
|
-
const reader = response.body.getReader();
|
|
3284
|
-
const decoder = new TextDecoder("utf-8");
|
|
3285
|
-
let buffer = "";
|
|
3286
3296
|
try {
|
|
3287
|
-
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
const lines = buffer.split("\n");
|
|
3292
|
-
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
3293
|
-
for (const line of lines) {
|
|
3294
|
-
const trimmed = line.trim();
|
|
3295
|
-
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
3296
|
-
if (!trimmed.startsWith("data:")) continue;
|
|
3297
|
-
try {
|
|
3298
|
-
const json = JSON.parse(trimmed.slice(5).trim());
|
|
3299
|
-
const text = resolvePath(json, extractPath);
|
|
3300
|
-
if (text && typeof text === "string") yield text;
|
|
3301
|
-
} catch (e) {
|
|
3302
|
-
}
|
|
3303
|
-
}
|
|
3297
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3298
|
+
const chunk = temp.value;
|
|
3299
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3300
|
+
if (content) yield content;
|
|
3304
3301
|
}
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3302
|
+
} catch (temp) {
|
|
3303
|
+
error = [temp];
|
|
3304
|
+
} finally {
|
|
3305
|
+
try {
|
|
3306
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3307
|
+
} finally {
|
|
3308
|
+
if (error)
|
|
3309
|
+
throw error[0];
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
async embed(text, options) {
|
|
3315
|
+
void text;
|
|
3316
|
+
void options;
|
|
3317
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3318
|
+
}
|
|
3319
|
+
async batchEmbed(texts, options) {
|
|
3320
|
+
void texts;
|
|
3321
|
+
void options;
|
|
3322
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3323
|
+
}
|
|
3324
|
+
async ping() {
|
|
3325
|
+
try {
|
|
3326
|
+
await this.client.models.list();
|
|
3327
|
+
return true;
|
|
3328
|
+
} catch (err) {
|
|
3329
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3330
|
+
return false;
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
};
|
|
3334
|
+
|
|
3335
|
+
// src/llm/providers/QwenProvider.ts
|
|
3336
|
+
import OpenAI3 from "openai";
|
|
3337
|
+
var QwenProvider = class {
|
|
3338
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3339
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3340
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3341
|
+
this.client = new OpenAI3({
|
|
3342
|
+
apiKey,
|
|
3343
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3344
|
+
});
|
|
3345
|
+
this.llmConfig = llmConfig;
|
|
3346
|
+
this.embeddingConfig = embeddingConfig;
|
|
3347
|
+
}
|
|
3348
|
+
static getValidator() {
|
|
3349
|
+
return {
|
|
3350
|
+
validate(config) {
|
|
3351
|
+
const errors = [];
|
|
3352
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3353
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3354
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3355
|
+
errors.push({
|
|
3356
|
+
field: `${prefix}.apiKey`,
|
|
3357
|
+
message: "Qwen API key is required",
|
|
3358
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3359
|
+
severity: "error"
|
|
3360
|
+
});
|
|
3361
|
+
}
|
|
3362
|
+
if (!config.model) {
|
|
3363
|
+
errors.push({
|
|
3364
|
+
field: `${prefix}.model`,
|
|
3365
|
+
message: "Qwen model name is required",
|
|
3366
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3367
|
+
severity: "error"
|
|
3368
|
+
});
|
|
3369
|
+
}
|
|
3370
|
+
return errors;
|
|
3371
|
+
}
|
|
3372
|
+
};
|
|
3373
|
+
}
|
|
3374
|
+
static getHealthChecker() {
|
|
3375
|
+
return {
|
|
3376
|
+
async check(config) {
|
|
3377
|
+
const timestamp = Date.now();
|
|
3378
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3379
|
+
const modelName = config.model;
|
|
3380
|
+
try {
|
|
3381
|
+
const OpenAI4 = await import("openai");
|
|
3382
|
+
const client = new OpenAI4.default({
|
|
3383
|
+
apiKey,
|
|
3384
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3385
|
+
});
|
|
3386
|
+
const models = await client.models.list();
|
|
3387
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3388
|
+
return {
|
|
3389
|
+
healthy: true,
|
|
3390
|
+
provider: "qwen",
|
|
3391
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3392
|
+
timestamp
|
|
3393
|
+
};
|
|
3394
|
+
} catch (error) {
|
|
3395
|
+
return {
|
|
3396
|
+
healthy: false,
|
|
3397
|
+
provider: "qwen",
|
|
3398
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3399
|
+
timestamp
|
|
3400
|
+
};
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
};
|
|
3404
|
+
}
|
|
3405
|
+
async chat(messages, context, options) {
|
|
3406
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3407
|
+
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.";
|
|
3408
|
+
const systemMessage = {
|
|
3409
|
+
role: "system",
|
|
3410
|
+
content: buildSystemContent(basePrompt, context)
|
|
3411
|
+
};
|
|
3412
|
+
const formattedMessages = [
|
|
3413
|
+
systemMessage,
|
|
3414
|
+
...messages.map((m) => ({
|
|
3415
|
+
role: m.role,
|
|
3416
|
+
content: m.content
|
|
3417
|
+
}))
|
|
3418
|
+
];
|
|
3419
|
+
const completion = await this.client.chat.completions.create({
|
|
3420
|
+
model: this.llmConfig.model,
|
|
3421
|
+
messages: formattedMessages,
|
|
3422
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3423
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3424
|
+
stop: options == null ? void 0 : options.stop
|
|
3425
|
+
});
|
|
3426
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3427
|
+
}
|
|
3428
|
+
chatStream(messages, context, options) {
|
|
3429
|
+
return __asyncGenerator(this, null, function* () {
|
|
3430
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3431
|
+
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.";
|
|
3432
|
+
const systemMessage = {
|
|
3433
|
+
role: "system",
|
|
3434
|
+
content: buildSystemContent(basePrompt, context)
|
|
3435
|
+
};
|
|
3436
|
+
const formattedMessages = [
|
|
3437
|
+
systemMessage,
|
|
3438
|
+
...messages.map((m) => ({
|
|
3439
|
+
role: m.role,
|
|
3440
|
+
content: m.content
|
|
3441
|
+
}))
|
|
3442
|
+
];
|
|
3443
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3444
|
+
model: this.llmConfig.model,
|
|
3445
|
+
messages: formattedMessages,
|
|
3446
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3447
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3448
|
+
stop: options == null ? void 0 : options.stop,
|
|
3449
|
+
stream: true
|
|
3450
|
+
}));
|
|
3451
|
+
if (!stream) {
|
|
3452
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3453
|
+
}
|
|
3454
|
+
try {
|
|
3455
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3456
|
+
const chunk = temp.value;
|
|
3457
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3458
|
+
if (content) yield content;
|
|
3459
|
+
}
|
|
3460
|
+
} catch (temp) {
|
|
3461
|
+
error = [temp];
|
|
3462
|
+
} finally {
|
|
3463
|
+
try {
|
|
3464
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3465
|
+
} finally {
|
|
3466
|
+
if (error)
|
|
3467
|
+
throw error[0];
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
async embed(text, options) {
|
|
3473
|
+
const results = await this.batchEmbed([text], options);
|
|
3474
|
+
return results[0];
|
|
3475
|
+
}
|
|
3476
|
+
async batchEmbed(texts, options) {
|
|
3477
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3478
|
+
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";
|
|
3479
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3480
|
+
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI3({
|
|
3481
|
+
apiKey,
|
|
3482
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3483
|
+
}) : this.client;
|
|
3484
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3485
|
+
return response.data.map((d) => d.embedding);
|
|
3486
|
+
}
|
|
3487
|
+
async ping() {
|
|
3488
|
+
try {
|
|
3489
|
+
await this.client.models.list();
|
|
3490
|
+
return true;
|
|
3491
|
+
} catch (err) {
|
|
3492
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3493
|
+
return false;
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3497
|
+
|
|
3498
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3499
|
+
init_templateUtils();
|
|
3500
|
+
import axios2 from "axios";
|
|
3501
|
+
|
|
3502
|
+
// src/config/UniversalProfiles.ts
|
|
3503
|
+
var OPENAI_BASE = {
|
|
3504
|
+
chatPath: "/chat/completions",
|
|
3505
|
+
embedPath: "/embeddings",
|
|
3506
|
+
responseExtractPath: "choices[0].message.content",
|
|
3507
|
+
embedExtractPath: "data[0].embedding",
|
|
3508
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3509
|
+
};
|
|
3510
|
+
var LLM_PROFILES = {
|
|
3511
|
+
"openai-compatible": OPENAI_BASE,
|
|
3512
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3513
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3514
|
+
}),
|
|
3515
|
+
"anthropic-claude": {
|
|
3516
|
+
chatPath: "/v1/messages",
|
|
3517
|
+
responseExtractPath: "content[0].text",
|
|
3518
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
3519
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3520
|
+
},
|
|
3521
|
+
"google-gemini": {
|
|
3522
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3523
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3524
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3525
|
+
},
|
|
3526
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3527
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3528
|
+
}),
|
|
3529
|
+
"ollama-standard": {
|
|
3530
|
+
chatPath: "/api/chat",
|
|
3531
|
+
embedPath: "/api/embeddings",
|
|
3532
|
+
responseExtractPath: "message.content",
|
|
3533
|
+
embedExtractPath: "embedding",
|
|
3534
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3535
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3536
|
+
}
|
|
3537
|
+
};
|
|
3538
|
+
|
|
3539
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3540
|
+
var UniversalLLMAdapter = class {
|
|
3541
|
+
constructor(config) {
|
|
3542
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3543
|
+
this.model = config.model;
|
|
3544
|
+
const llmConfig = config;
|
|
3545
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3546
|
+
let profile = {};
|
|
3547
|
+
if (typeof options.profile === "string") {
|
|
3548
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
3549
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3550
|
+
profile = options.profile;
|
|
3551
|
+
}
|
|
3552
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3553
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3554
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3555
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3556
|
+
this.apiKey = config.apiKey;
|
|
3557
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3558
|
+
if (!this.baseUrl) {
|
|
3559
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3560
|
+
}
|
|
3561
|
+
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3562
|
+
"Content-Type": "application/json"
|
|
3563
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3564
|
+
this.http = axios2.create({
|
|
3565
|
+
baseURL: this.baseUrl,
|
|
3566
|
+
headers: this.resolvedHeaders,
|
|
3567
|
+
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3568
|
+
});
|
|
3569
|
+
}
|
|
3570
|
+
async chat(messages, context) {
|
|
3571
|
+
var _a2, _b;
|
|
3572
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3573
|
+
const formattedMessages = [
|
|
3574
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3575
|
+
|
|
3576
|
+
Context:
|
|
3577
|
+
${context != null ? context : "None"}` },
|
|
3578
|
+
...messages
|
|
3579
|
+
];
|
|
3580
|
+
let payload;
|
|
3581
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3582
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3583
|
+
model: this.model,
|
|
3584
|
+
messages: formattedMessages,
|
|
3585
|
+
maxTokens: this.maxTokens,
|
|
3586
|
+
temperature: this.temperature
|
|
3587
|
+
});
|
|
3588
|
+
} else {
|
|
3589
|
+
payload = {
|
|
3590
|
+
model: this.model,
|
|
3591
|
+
messages: formattedMessages,
|
|
3592
|
+
max_tokens: this.maxTokens,
|
|
3593
|
+
temperature: this.temperature
|
|
3594
|
+
};
|
|
3595
|
+
}
|
|
3596
|
+
const { data } = await this.http.post(path2, payload);
|
|
3597
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3598
|
+
const result = resolvePath(data, extractPath);
|
|
3599
|
+
if (result === void 0) {
|
|
3600
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3601
|
+
}
|
|
3602
|
+
return String(result);
|
|
3603
|
+
}
|
|
3604
|
+
/**
|
|
3605
|
+
* Streaming chat using native fetch + ReadableStream.
|
|
3606
|
+
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3607
|
+
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3608
|
+
*/
|
|
3609
|
+
chatStream(messages, context) {
|
|
3610
|
+
return __asyncGenerator(this, null, function* () {
|
|
3611
|
+
var _a2, _b, _c;
|
|
3612
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3613
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3614
|
+
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3615
|
+
const formattedMessages = [
|
|
3616
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3617
|
+
|
|
3618
|
+
Context:
|
|
3619
|
+
${context != null ? context : "None"}` },
|
|
3620
|
+
...messages
|
|
3621
|
+
];
|
|
3622
|
+
let payload;
|
|
3623
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3624
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3625
|
+
model: this.model,
|
|
3626
|
+
messages: formattedMessages,
|
|
3627
|
+
maxTokens: this.maxTokens,
|
|
3628
|
+
temperature: this.temperature
|
|
3629
|
+
});
|
|
3630
|
+
if (typeof payload === "object" && payload !== null) {
|
|
3631
|
+
payload.stream = true;
|
|
3632
|
+
}
|
|
3633
|
+
} else {
|
|
3634
|
+
payload = {
|
|
3635
|
+
model: this.model,
|
|
3636
|
+
messages: formattedMessages,
|
|
3637
|
+
max_tokens: this.maxTokens,
|
|
3638
|
+
temperature: this.temperature,
|
|
3639
|
+
stream: true
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
const response = yield new __await(fetch(url, {
|
|
3643
|
+
method: "POST",
|
|
3644
|
+
headers: this.resolvedHeaders,
|
|
3645
|
+
body: JSON.stringify(payload)
|
|
3646
|
+
}));
|
|
3647
|
+
if (!response.ok) {
|
|
3648
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
3649
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3650
|
+
}
|
|
3651
|
+
if (!response.body) {
|
|
3652
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3653
|
+
}
|
|
3654
|
+
const reader = response.body.getReader();
|
|
3655
|
+
const decoder = new TextDecoder("utf-8");
|
|
3656
|
+
let buffer = "";
|
|
3657
|
+
try {
|
|
3658
|
+
while (true) {
|
|
3659
|
+
const { done, value } = yield new __await(reader.read());
|
|
3660
|
+
if (done) break;
|
|
3661
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3662
|
+
const lines = buffer.split("\n");
|
|
3663
|
+
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
3664
|
+
for (const line of lines) {
|
|
3665
|
+
const trimmed = line.trim();
|
|
3666
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
3667
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
3668
|
+
try {
|
|
3669
|
+
const json = JSON.parse(trimmed.slice(5).trim());
|
|
3670
|
+
const text = resolvePath(json, extractPath);
|
|
3671
|
+
if (text && typeof text === "string") yield text;
|
|
3672
|
+
} catch (e) {
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
if (buffer.trim() && buffer.trim() !== "data: [DONE]") {
|
|
3677
|
+
const jsonStr = buffer.replace(/^data:\s*/, "").trim();
|
|
3678
|
+
try {
|
|
3679
|
+
const json = JSON.parse(jsonStr);
|
|
3680
|
+
const text = resolvePath(json, extractPath);
|
|
3681
|
+
if (text && typeof text === "string") yield text;
|
|
3311
3682
|
} catch (e) {
|
|
3312
3683
|
}
|
|
3313
3684
|
}
|
|
@@ -3317,8 +3688,8 @@ ${context != null ? context : "None"}` },
|
|
|
3317
3688
|
});
|
|
3318
3689
|
}
|
|
3319
3690
|
async embed(text) {
|
|
3320
|
-
var
|
|
3321
|
-
const
|
|
3691
|
+
var _a2, _b;
|
|
3692
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3322
3693
|
let payload;
|
|
3323
3694
|
if (this.opts.embedPayloadTemplate) {
|
|
3324
3695
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3331,7 +3702,7 @@ ${context != null ? context : "None"}` },
|
|
|
3331
3702
|
input: text
|
|
3332
3703
|
};
|
|
3333
3704
|
}
|
|
3334
|
-
const { data } = await this.http.post(
|
|
3705
|
+
const { data } = await this.http.post(path2, payload);
|
|
3335
3706
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3336
3707
|
const vector = resolvePath(data, extractPath);
|
|
3337
3708
|
if (!Array.isArray(vector)) {
|
|
@@ -3399,13 +3770,13 @@ var AuthenticationException = class extends RetrivoraError {
|
|
|
3399
3770
|
}
|
|
3400
3771
|
};
|
|
3401
3772
|
function wrapError(err, defaultCode, defaultMessage) {
|
|
3402
|
-
var
|
|
3773
|
+
var _a2;
|
|
3403
3774
|
if (err instanceof RetrivoraError) {
|
|
3404
3775
|
return err;
|
|
3405
3776
|
}
|
|
3406
3777
|
const error = err;
|
|
3407
3778
|
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3408
|
-
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((
|
|
3779
|
+
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);
|
|
3409
3780
|
const code = error == null ? void 0 : error.code;
|
|
3410
3781
|
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3411
3782
|
return new RateLimitException(message, err);
|
|
@@ -3469,6 +3840,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3469
3840
|
"anthropic",
|
|
3470
3841
|
"ollama",
|
|
3471
3842
|
"gemini",
|
|
3843
|
+
"groq",
|
|
3844
|
+
"qwen",
|
|
3472
3845
|
"rest",
|
|
3473
3846
|
"universal_rest",
|
|
3474
3847
|
"custom",
|
|
@@ -3476,7 +3849,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3476
3849
|
];
|
|
3477
3850
|
}
|
|
3478
3851
|
static create(llmConfig, embeddingConfig) {
|
|
3479
|
-
var
|
|
3852
|
+
var _a2, _b, _c;
|
|
3480
3853
|
switch (llmConfig.provider) {
|
|
3481
3854
|
case "openai":
|
|
3482
3855
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3486,12 +3859,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3486
3859
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3487
3860
|
case "gemini":
|
|
3488
3861
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3862
|
+
case "groq":
|
|
3863
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3864
|
+
case "qwen":
|
|
3865
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3489
3866
|
case "rest":
|
|
3490
3867
|
case "universal_rest":
|
|
3491
3868
|
case "custom":
|
|
3492
3869
|
return new UniversalLLMAdapter(llmConfig);
|
|
3493
3870
|
default: {
|
|
3494
|
-
const providerName = String((
|
|
3871
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3495
3872
|
const customFactory = customProviders.get(providerName);
|
|
3496
3873
|
if (customFactory) {
|
|
3497
3874
|
return customFactory(llmConfig);
|
|
@@ -3528,6 +3905,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3528
3905
|
return OllamaProvider;
|
|
3529
3906
|
case "gemini":
|
|
3530
3907
|
return GeminiProvider;
|
|
3908
|
+
case "groq":
|
|
3909
|
+
return GroqProvider;
|
|
3910
|
+
case "qwen":
|
|
3911
|
+
return QwenProvider;
|
|
3531
3912
|
case "rest":
|
|
3532
3913
|
case "universal_rest":
|
|
3533
3914
|
case "custom":
|
|
@@ -3589,7 +3970,7 @@ var ProviderRegistry = class {
|
|
|
3589
3970
|
return null;
|
|
3590
3971
|
}
|
|
3591
3972
|
static async loadVectorProviderClass(provider) {
|
|
3592
|
-
var
|
|
3973
|
+
var _a2;
|
|
3593
3974
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3594
3975
|
switch (provider) {
|
|
3595
3976
|
case "pinecone": {
|
|
@@ -3598,7 +3979,7 @@ var ProviderRegistry = class {
|
|
|
3598
3979
|
}
|
|
3599
3980
|
case "pgvector":
|
|
3600
3981
|
case "postgresql": {
|
|
3601
|
-
const postgresMode = ((
|
|
3982
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3602
3983
|
if (postgresMode === "single") {
|
|
3603
3984
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3604
3985
|
return PostgreSQLProvider2;
|
|
@@ -4047,11 +4428,11 @@ var LlamaIndexIngestor = class {
|
|
|
4047
4428
|
* than standard character-count splitting.
|
|
4048
4429
|
*/
|
|
4049
4430
|
async chunk(text, options = {}) {
|
|
4050
|
-
var
|
|
4431
|
+
var _a2, _b;
|
|
4051
4432
|
try {
|
|
4052
4433
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4053
4434
|
const splitter = new SentenceSplitter({
|
|
4054
|
-
chunkSize: (
|
|
4435
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4055
4436
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4056
4437
|
});
|
|
4057
4438
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4160,7 +4541,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4160
4541
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4161
4542
|
*/
|
|
4162
4543
|
async run(input, chatHistory = []) {
|
|
4163
|
-
var
|
|
4544
|
+
var _a2, _b, _c;
|
|
4164
4545
|
if (!this.agent) {
|
|
4165
4546
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4166
4547
|
}
|
|
@@ -4171,7 +4552,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4171
4552
|
const response = await this.agent.invoke({
|
|
4172
4553
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4173
4554
|
});
|
|
4174
|
-
const lastMessage = (
|
|
4555
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4175
4556
|
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4176
4557
|
return lastMessage.content;
|
|
4177
4558
|
}
|
|
@@ -4182,6 +4563,437 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4182
4563
|
}
|
|
4183
4564
|
};
|
|
4184
4565
|
|
|
4566
|
+
// src/core/mcp.ts
|
|
4567
|
+
import { spawn } from "child_process";
|
|
4568
|
+
var MCPClient = class {
|
|
4569
|
+
constructor(config) {
|
|
4570
|
+
this.config = config;
|
|
4571
|
+
this.messageIdCounter = 0;
|
|
4572
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4573
|
+
this.stdioBuffer = "";
|
|
4574
|
+
this.initialized = false;
|
|
4575
|
+
}
|
|
4576
|
+
getNextMessageId() {
|
|
4577
|
+
return ++this.messageIdCounter;
|
|
4578
|
+
}
|
|
4579
|
+
/**
|
|
4580
|
+
* Connect and initialize the MCP server connection.
|
|
4581
|
+
*/
|
|
4582
|
+
async connect() {
|
|
4583
|
+
if (this.initialized) return;
|
|
4584
|
+
if (this.config.transport === "stdio") {
|
|
4585
|
+
await this.connectStdio();
|
|
4586
|
+
} else {
|
|
4587
|
+
await this.connectSSE();
|
|
4588
|
+
}
|
|
4589
|
+
try {
|
|
4590
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4591
|
+
protocolVersion: "2024-11-05",
|
|
4592
|
+
capabilities: {},
|
|
4593
|
+
clientInfo: {
|
|
4594
|
+
name: "retrivora-sdk",
|
|
4595
|
+
version: "1.0.0"
|
|
4596
|
+
}
|
|
4597
|
+
});
|
|
4598
|
+
await this.sendNotification("notifications/initialized");
|
|
4599
|
+
this.initialized = true;
|
|
4600
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4601
|
+
} catch (err) {
|
|
4602
|
+
this.disconnect();
|
|
4603
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
async connectStdio() {
|
|
4607
|
+
var _a2;
|
|
4608
|
+
const cmd = this.config.command;
|
|
4609
|
+
if (!cmd) {
|
|
4610
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4611
|
+
}
|
|
4612
|
+
const args = this.config.args || [];
|
|
4613
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4614
|
+
this.childProcess = spawn(cmd, args, { env, shell: true });
|
|
4615
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4616
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4617
|
+
}
|
|
4618
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4619
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4620
|
+
this.processStdioLines();
|
|
4621
|
+
});
|
|
4622
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4623
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4624
|
+
});
|
|
4625
|
+
this.childProcess.on("close", (code) => {
|
|
4626
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4627
|
+
this.disconnect();
|
|
4628
|
+
});
|
|
4629
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4630
|
+
}
|
|
4631
|
+
processStdioLines() {
|
|
4632
|
+
let newlineIndex;
|
|
4633
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4634
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4635
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4636
|
+
if (!line) continue;
|
|
4637
|
+
try {
|
|
4638
|
+
const payload = JSON.parse(line);
|
|
4639
|
+
if (payload.id !== void 0) {
|
|
4640
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4641
|
+
if (req) {
|
|
4642
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4643
|
+
if (payload.error) {
|
|
4644
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4645
|
+
} else {
|
|
4646
|
+
req.resolve(payload.result);
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
} catch (e) {
|
|
4651
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
async connectSSE() {
|
|
4656
|
+
if (!this.config.url) {
|
|
4657
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4658
|
+
}
|
|
4659
|
+
this.sseUrl = this.config.url;
|
|
4660
|
+
}
|
|
4661
|
+
async sendJsonRpc(method, params) {
|
|
4662
|
+
const id = this.getNextMessageId();
|
|
4663
|
+
const request = {
|
|
4664
|
+
jsonrpc: "2.0",
|
|
4665
|
+
id,
|
|
4666
|
+
method,
|
|
4667
|
+
params
|
|
4668
|
+
};
|
|
4669
|
+
if (this.config.transport === "stdio") {
|
|
4670
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4671
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4672
|
+
}
|
|
4673
|
+
return new Promise((resolve, reject) => {
|
|
4674
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4675
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4676
|
+
});
|
|
4677
|
+
} else {
|
|
4678
|
+
if (!this.sseUrl) {
|
|
4679
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4680
|
+
}
|
|
4681
|
+
const response = await fetch(this.sseUrl, {
|
|
4682
|
+
method: "POST",
|
|
4683
|
+
headers: { "Content-Type": "application/json" },
|
|
4684
|
+
body: JSON.stringify(request)
|
|
4685
|
+
});
|
|
4686
|
+
if (!response.ok) {
|
|
4687
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4688
|
+
}
|
|
4689
|
+
const payload = await response.json();
|
|
4690
|
+
if (payload.error) {
|
|
4691
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4692
|
+
}
|
|
4693
|
+
return payload.result;
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4696
|
+
async sendNotification(method, params) {
|
|
4697
|
+
var _a2;
|
|
4698
|
+
const notification = {
|
|
4699
|
+
jsonrpc: "2.0",
|
|
4700
|
+
method,
|
|
4701
|
+
params
|
|
4702
|
+
};
|
|
4703
|
+
if (this.config.transport === "stdio") {
|
|
4704
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4705
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4706
|
+
}
|
|
4707
|
+
} else if (this.sseUrl) {
|
|
4708
|
+
await fetch(this.sseUrl, {
|
|
4709
|
+
method: "POST",
|
|
4710
|
+
headers: { "Content-Type": "application/json" },
|
|
4711
|
+
body: JSON.stringify(notification)
|
|
4712
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4713
|
+
}
|
|
4714
|
+
}
|
|
4715
|
+
/**
|
|
4716
|
+
* List all tools offered by the MCP server.
|
|
4717
|
+
*/
|
|
4718
|
+
async listTools() {
|
|
4719
|
+
await this.connect();
|
|
4720
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4721
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4722
|
+
}
|
|
4723
|
+
/**
|
|
4724
|
+
* Execute a tool on the MCP server.
|
|
4725
|
+
*/
|
|
4726
|
+
async callTool(name, args = {}) {
|
|
4727
|
+
await this.connect();
|
|
4728
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4729
|
+
}
|
|
4730
|
+
disconnect() {
|
|
4731
|
+
this.initialized = false;
|
|
4732
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4733
|
+
this.pendingRequests.clear();
|
|
4734
|
+
if (this.childProcess) {
|
|
4735
|
+
try {
|
|
4736
|
+
this.childProcess.kill();
|
|
4737
|
+
} catch (e) {
|
|
4738
|
+
}
|
|
4739
|
+
this.childProcess = void 0;
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
};
|
|
4743
|
+
var MCPRegistry = class {
|
|
4744
|
+
constructor(servers = []) {
|
|
4745
|
+
this.clients = [];
|
|
4746
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4747
|
+
}
|
|
4748
|
+
async getAllTools() {
|
|
4749
|
+
const list = [];
|
|
4750
|
+
await Promise.all(
|
|
4751
|
+
this.clients.map(async (client) => {
|
|
4752
|
+
try {
|
|
4753
|
+
const tools = await client.listTools();
|
|
4754
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4755
|
+
} catch (e) {
|
|
4756
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4757
|
+
}
|
|
4758
|
+
})
|
|
4759
|
+
);
|
|
4760
|
+
return list;
|
|
4761
|
+
}
|
|
4762
|
+
async callTool(toolName, args = {}) {
|
|
4763
|
+
for (const client of this.clients) {
|
|
4764
|
+
try {
|
|
4765
|
+
const tools = await client.listTools();
|
|
4766
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4767
|
+
return await client.callTool(toolName, args);
|
|
4768
|
+
}
|
|
4769
|
+
} catch (e) {
|
|
4770
|
+
}
|
|
4771
|
+
}
|
|
4772
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4773
|
+
}
|
|
4774
|
+
disconnectAll() {
|
|
4775
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4776
|
+
}
|
|
4777
|
+
};
|
|
4778
|
+
|
|
4779
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4780
|
+
var MultiAgentCoordinator = class {
|
|
4781
|
+
constructor(options) {
|
|
4782
|
+
var _a2;
|
|
4783
|
+
this.llmProvider = options.llmProvider;
|
|
4784
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4785
|
+
this.documentSearch = options.documentSearch;
|
|
4786
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
4787
|
+
}
|
|
4788
|
+
/**
|
|
4789
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
4790
|
+
*/
|
|
4791
|
+
async run(question, history = []) {
|
|
4792
|
+
const generator = this.runStream(question, history);
|
|
4793
|
+
let finalReply = "";
|
|
4794
|
+
const sources = [];
|
|
4795
|
+
try {
|
|
4796
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4797
|
+
const chunk = temp.value;
|
|
4798
|
+
if (typeof chunk === "string") {
|
|
4799
|
+
finalReply += chunk;
|
|
4800
|
+
} else if (chunk && typeof chunk === "object") {
|
|
4801
|
+
if ("reply" in chunk && chunk.reply) {
|
|
4802
|
+
finalReply += chunk.reply;
|
|
4803
|
+
}
|
|
4804
|
+
if ("sources" in chunk && chunk.sources) {
|
|
4805
|
+
sources.push(...chunk.sources);
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
} catch (temp) {
|
|
4810
|
+
error = [temp];
|
|
4811
|
+
} finally {
|
|
4812
|
+
try {
|
|
4813
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4814
|
+
} finally {
|
|
4815
|
+
if (error)
|
|
4816
|
+
throw error[0];
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
return {
|
|
4820
|
+
reply: finalReply,
|
|
4821
|
+
sources
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
4826
|
+
*/
|
|
4827
|
+
runStream(_0) {
|
|
4828
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
4829
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
4830
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
4831
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
4832
|
+
|
|
4833
|
+
Available Tools:
|
|
4834
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
4835
|
+
|
|
4836
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
4837
|
+
${mcpTools.map((mt) => {
|
|
4838
|
+
var _a2;
|
|
4839
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
4840
|
+
}).join("\n")}
|
|
4841
|
+
|
|
4842
|
+
Tool Calling Protocol:
|
|
4843
|
+
If you need to call a tool, write:
|
|
4844
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
4845
|
+
And then STOP generating immediately.
|
|
4846
|
+
|
|
4847
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
4848
|
+
`;
|
|
4849
|
+
const supervisorHistory = [
|
|
4850
|
+
{ role: "system", content: systemPrompt },
|
|
4851
|
+
...history,
|
|
4852
|
+
{ role: "user", content: question }
|
|
4853
|
+
];
|
|
4854
|
+
let iteration = 0;
|
|
4855
|
+
const allSources = [];
|
|
4856
|
+
while (iteration < this.maxIterations) {
|
|
4857
|
+
iteration++;
|
|
4858
|
+
const context = "";
|
|
4859
|
+
let fullModelResponse = "";
|
|
4860
|
+
let textBuffer = "";
|
|
4861
|
+
let inThinking = false;
|
|
4862
|
+
let toolCallDetected = null;
|
|
4863
|
+
if (!this.llmProvider.chatStream) {
|
|
4864
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
4865
|
+
fullModelResponse = reply;
|
|
4866
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
4867
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
4868
|
+
let thinkingText = "";
|
|
4869
|
+
let answerText = reply;
|
|
4870
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
4871
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
4872
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
4873
|
+
yield { type: "thinking", text: thinkingText };
|
|
4874
|
+
}
|
|
4875
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4876
|
+
if (toolMatch) {
|
|
4877
|
+
const toolName = toolMatch[1];
|
|
4878
|
+
const toolArgsStr = toolMatch[2];
|
|
4879
|
+
try {
|
|
4880
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4881
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4882
|
+
} catch (e) {
|
|
4883
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4884
|
+
}
|
|
4885
|
+
} else {
|
|
4886
|
+
yield answerText;
|
|
4887
|
+
}
|
|
4888
|
+
} else {
|
|
4889
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
4890
|
+
try {
|
|
4891
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
4892
|
+
const chunk = temp.value;
|
|
4893
|
+
fullModelResponse += chunk;
|
|
4894
|
+
textBuffer += chunk;
|
|
4895
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
4896
|
+
inThinking = true;
|
|
4897
|
+
const idx = textBuffer.indexOf("<think>");
|
|
4898
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
4899
|
+
}
|
|
4900
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
4901
|
+
inThinking = false;
|
|
4902
|
+
const idx = textBuffer.indexOf("</think>");
|
|
4903
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
4904
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
4905
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
4906
|
+
}
|
|
4907
|
+
if (inThinking && textBuffer.length > 0) {
|
|
4908
|
+
yield { type: "thinking", text: textBuffer };
|
|
4909
|
+
textBuffer = "";
|
|
4910
|
+
}
|
|
4911
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
4912
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
4913
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
4914
|
+
if (precedingText.trim()) {
|
|
4915
|
+
yield precedingText;
|
|
4916
|
+
}
|
|
4917
|
+
textBuffer = textBuffer.slice(idx);
|
|
4918
|
+
}
|
|
4919
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
4920
|
+
yield textBuffer;
|
|
4921
|
+
textBuffer = "";
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
} catch (temp) {
|
|
4925
|
+
error = [temp];
|
|
4926
|
+
} finally {
|
|
4927
|
+
try {
|
|
4928
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
4929
|
+
} finally {
|
|
4930
|
+
if (error)
|
|
4931
|
+
throw error[0];
|
|
4932
|
+
}
|
|
4933
|
+
}
|
|
4934
|
+
if (textBuffer.trim()) {
|
|
4935
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4936
|
+
if (toolMatch) {
|
|
4937
|
+
const toolName = toolMatch[1];
|
|
4938
|
+
const toolArgsStr = toolMatch[2];
|
|
4939
|
+
try {
|
|
4940
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4941
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4942
|
+
} catch (e) {
|
|
4943
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4944
|
+
}
|
|
4945
|
+
} else {
|
|
4946
|
+
yield textBuffer;
|
|
4947
|
+
}
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
4951
|
+
if (toolCallDetected) {
|
|
4952
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
4953
|
+
yield {
|
|
4954
|
+
type: "thinking",
|
|
4955
|
+
text: `
|
|
4956
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
4957
|
+
`
|
|
4958
|
+
};
|
|
4959
|
+
let toolResultText = "";
|
|
4960
|
+
try {
|
|
4961
|
+
if (toolName === "document_search") {
|
|
4962
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
4963
|
+
toolResultText = `document_search returned:
|
|
4964
|
+
${searchRes.reply}
|
|
4965
|
+
|
|
4966
|
+
Sources count: ${searchRes.sources.length}`;
|
|
4967
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
4968
|
+
allSources.push(...searchRes.sources);
|
|
4969
|
+
yield { reply: "", sources: searchRes.sources };
|
|
4970
|
+
}
|
|
4971
|
+
} else {
|
|
4972
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
4973
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
4974
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
4975
|
+
}
|
|
4976
|
+
} catch (err) {
|
|
4977
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
4978
|
+
}
|
|
4979
|
+
supervisorHistory.push({
|
|
4980
|
+
role: "user",
|
|
4981
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
4982
|
+
${toolResultText}`
|
|
4983
|
+
});
|
|
4984
|
+
yield {
|
|
4985
|
+
type: "thinking",
|
|
4986
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
4987
|
+
`
|
|
4988
|
+
};
|
|
4989
|
+
} else {
|
|
4990
|
+
break;
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
});
|
|
4994
|
+
}
|
|
4995
|
+
};
|
|
4996
|
+
|
|
4185
4997
|
// src/core/BatchProcessor.ts
|
|
4186
4998
|
function isTransientError(error) {
|
|
4187
4999
|
if (!(error instanceof Error)) return false;
|
|
@@ -4502,7 +5314,7 @@ var QueryProcessor = class {
|
|
|
4502
5314
|
* @param validFields Optional list of known filterable fields to look for
|
|
4503
5315
|
*/
|
|
4504
5316
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4505
|
-
var
|
|
5317
|
+
var _a2, _b, _c, _d;
|
|
4506
5318
|
if (!question.trim()) return [];
|
|
4507
5319
|
const hints = /* @__PURE__ */ new Map();
|
|
4508
5320
|
const addHint = (value, field) => {
|
|
@@ -4582,7 +5394,7 @@ var QueryProcessor = class {
|
|
|
4582
5394
|
];
|
|
4583
5395
|
for (const p of universalPatterns) {
|
|
4584
5396
|
for (const match of question.matchAll(p.regex)) {
|
|
4585
|
-
const val = p.group ? (
|
|
5397
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4586
5398
|
if (!val) continue;
|
|
4587
5399
|
if (p.field) addHint(val, p.field);
|
|
4588
5400
|
else addHint(val);
|
|
@@ -4806,11 +5618,11 @@ var LLMRouter = class {
|
|
|
4806
5618
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4807
5619
|
*/
|
|
4808
5620
|
async initialize(prebuiltDefault) {
|
|
4809
|
-
var
|
|
5621
|
+
var _a2;
|
|
4810
5622
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4811
5623
|
this.models.set("default", defaultModel);
|
|
4812
5624
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4813
|
-
const providerFastDefault = (
|
|
5625
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4814
5626
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4815
5627
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4816
5628
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4829,8 +5641,8 @@ var LLMRouter = class {
|
|
|
4829
5641
|
* Falls back to 'default' if the requested role is not registered.
|
|
4830
5642
|
*/
|
|
4831
5643
|
get(role) {
|
|
4832
|
-
var
|
|
4833
|
-
const provider = (
|
|
5644
|
+
var _a2;
|
|
5645
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4834
5646
|
if (!provider) {
|
|
4835
5647
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4836
5648
|
}
|
|
@@ -4848,7 +5660,7 @@ var UITransformer = class _UITransformer {
|
|
|
4848
5660
|
* Prefer `analyzeAndDecide()` in production.
|
|
4849
5661
|
*/
|
|
4850
5662
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4851
|
-
var
|
|
5663
|
+
var _a2, _b, _c;
|
|
4852
5664
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4853
5665
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4854
5666
|
}
|
|
@@ -4868,7 +5680,7 @@ var UITransformer = class _UITransformer {
|
|
|
4868
5680
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4869
5681
|
}
|
|
4870
5682
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4871
|
-
return (
|
|
5683
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4872
5684
|
}
|
|
4873
5685
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4874
5686
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5193,11 +6005,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5193
6005
|
};
|
|
5194
6006
|
}
|
|
5195
6007
|
static transformToPieChart(data, profile, query = "") {
|
|
5196
|
-
var
|
|
6008
|
+
var _a2;
|
|
5197
6009
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5198
6010
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5199
|
-
var
|
|
5200
|
-
return String((
|
|
6011
|
+
var _a3;
|
|
6012
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5201
6013
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5202
6014
|
if (categories.length === 0) return null;
|
|
5203
6015
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5207,7 +6019,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5207
6019
|
});
|
|
5208
6020
|
return {
|
|
5209
6021
|
type: "pie_chart",
|
|
5210
|
-
title: `Distribution by ${(
|
|
6022
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5211
6023
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5212
6024
|
data: pieData
|
|
5213
6025
|
};
|
|
@@ -5217,8 +6029,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5217
6029
|
const valueField = profile.numericFields[0];
|
|
5218
6030
|
const buckets = /* @__PURE__ */ new Map();
|
|
5219
6031
|
profile.records.forEach((record) => {
|
|
5220
|
-
var
|
|
5221
|
-
const timestamp = String((
|
|
6032
|
+
var _a2, _b, _c;
|
|
6033
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5222
6034
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5223
6035
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5224
6036
|
});
|
|
@@ -5231,23 +6043,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5231
6043
|
};
|
|
5232
6044
|
}
|
|
5233
6045
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5234
|
-
var
|
|
6046
|
+
var _a2;
|
|
5235
6047
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5236
6048
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5237
6049
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5238
6050
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5239
6051
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5240
|
-
var
|
|
6052
|
+
var _a3, _b, _c, _d, _e;
|
|
5241
6053
|
const meta = item.metadata || {};
|
|
5242
6054
|
const label = String(
|
|
5243
|
-
(_c = (_b = (
|
|
6055
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5244
6056
|
);
|
|
5245
6057
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5246
6058
|
return { category: label, value: Number(value) };
|
|
5247
6059
|
});
|
|
5248
6060
|
return {
|
|
5249
6061
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5250
|
-
title: dimension ? `${(
|
|
6062
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5251
6063
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5252
6064
|
data: fallbackData
|
|
5253
6065
|
};
|
|
@@ -5282,11 +6094,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5282
6094
|
if (fields.length < 2) return null;
|
|
5283
6095
|
const [xField, yField] = fields;
|
|
5284
6096
|
const points = profile.records.map((record) => {
|
|
5285
|
-
var
|
|
6097
|
+
var _a2;
|
|
5286
6098
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5287
6099
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5288
6100
|
if (x === null || y === null) return null;
|
|
5289
|
-
return { x, y, label: String((
|
|
6101
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5290
6102
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5291
6103
|
if (points.length === 0) return null;
|
|
5292
6104
|
return {
|
|
@@ -5316,9 +6128,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5316
6128
|
static transformToRadarChart(data) {
|
|
5317
6129
|
const attributeMap = {};
|
|
5318
6130
|
data.forEach((item) => {
|
|
5319
|
-
var
|
|
6131
|
+
var _a2, _b, _c;
|
|
5320
6132
|
const meta = item.metadata || {};
|
|
5321
|
-
const seriesName = String((_c = (_b = (
|
|
6133
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5322
6134
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5323
6135
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5324
6136
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5400,22 +6212,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5400
6212
|
return null;
|
|
5401
6213
|
}
|
|
5402
6214
|
static normalizeTransformation(payload) {
|
|
5403
|
-
var
|
|
6215
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5404
6216
|
if (!payload || typeof payload !== "object") return null;
|
|
5405
6217
|
const p = payload;
|
|
5406
6218
|
const type = this.normalizeVisualizationType(
|
|
5407
|
-
String((_c = (_b = (
|
|
6219
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5408
6220
|
);
|
|
5409
6221
|
if (!type) return null;
|
|
5410
6222
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5411
6223
|
const description = p.description ? String(p.description) : void 0;
|
|
5412
|
-
const rawData = (_j = (_i = (_h = (
|
|
6224
|
+
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;
|
|
5413
6225
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5414
6226
|
const transformation = { type, title, description, data };
|
|
5415
6227
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5416
6228
|
}
|
|
5417
6229
|
static normalizeVisualizationType(type) {
|
|
5418
|
-
var
|
|
6230
|
+
var _a2;
|
|
5419
6231
|
const mapping = {
|
|
5420
6232
|
pie: "pie_chart",
|
|
5421
6233
|
pie_chart: "pie_chart",
|
|
@@ -5443,7 +6255,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5443
6255
|
product_carousel: "product_carousel",
|
|
5444
6256
|
carousel: "carousel"
|
|
5445
6257
|
};
|
|
5446
|
-
return (
|
|
6258
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5447
6259
|
}
|
|
5448
6260
|
static validateTransformation(t) {
|
|
5449
6261
|
const { type, data } = t;
|
|
@@ -5645,16 +6457,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5645
6457
|
return null;
|
|
5646
6458
|
}
|
|
5647
6459
|
static selectDimensionField(profile, query) {
|
|
5648
|
-
var
|
|
6460
|
+
var _a2, _b;
|
|
5649
6461
|
const productCategory = profile.categoricalFields.find(
|
|
5650
6462
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5651
6463
|
);
|
|
5652
6464
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5653
|
-
return (_b = (
|
|
6465
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5654
6466
|
}
|
|
5655
6467
|
static selectNumericField(profile, query) {
|
|
5656
|
-
var
|
|
5657
|
-
return (
|
|
6468
|
+
var _a2;
|
|
6469
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5658
6470
|
}
|
|
5659
6471
|
static rankFieldsByQuery(fields, query) {
|
|
5660
6472
|
const q = query.toLowerCase();
|
|
@@ -5683,8 +6495,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5683
6495
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5684
6496
|
const result = {};
|
|
5685
6497
|
profile.records.forEach((record) => {
|
|
5686
|
-
var
|
|
5687
|
-
const category = String((
|
|
6498
|
+
var _a2, _b, _c;
|
|
6499
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5688
6500
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5689
6501
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5690
6502
|
});
|
|
@@ -5763,8 +6575,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5763
6575
|
static aggregateByCategory(data, categories) {
|
|
5764
6576
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5765
6577
|
data.forEach((item) => {
|
|
5766
|
-
var
|
|
5767
|
-
const cat = (
|
|
6578
|
+
var _a2;
|
|
6579
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5768
6580
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5769
6581
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5770
6582
|
});
|
|
@@ -5772,17 +6584,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5772
6584
|
}
|
|
5773
6585
|
static extractTimeSeriesData(data) {
|
|
5774
6586
|
return data.map((item) => {
|
|
5775
|
-
var
|
|
6587
|
+
var _a2, _b, _c, _d, _e;
|
|
5776
6588
|
const meta = item.metadata || {};
|
|
5777
6589
|
return {
|
|
5778
|
-
timestamp: (_b = (
|
|
6590
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5779
6591
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5780
6592
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5781
6593
|
};
|
|
5782
6594
|
});
|
|
5783
6595
|
}
|
|
5784
6596
|
static extractNumericValue(meta) {
|
|
5785
|
-
var
|
|
6597
|
+
var _a2;
|
|
5786
6598
|
const preferredKeys = [
|
|
5787
6599
|
"value",
|
|
5788
6600
|
"count",
|
|
@@ -5797,7 +6609,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5797
6609
|
"price"
|
|
5798
6610
|
];
|
|
5799
6611
|
for (const key of preferredKeys) {
|
|
5800
|
-
const raw = (
|
|
6612
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5801
6613
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5802
6614
|
if (Number.isFinite(value)) return value;
|
|
5803
6615
|
}
|
|
@@ -5943,8 +6755,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5943
6755
|
let inStock = 0;
|
|
5944
6756
|
let outOfStock = 0;
|
|
5945
6757
|
data.forEach((d) => {
|
|
5946
|
-
var
|
|
5947
|
-
const cat = (
|
|
6758
|
+
var _a2, _b;
|
|
6759
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
5948
6760
|
if (cat === category) {
|
|
5949
6761
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
5950
6762
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -5988,9 +6800,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5988
6800
|
}
|
|
5989
6801
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
5990
6802
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
5991
|
-
var
|
|
6803
|
+
var _a2;
|
|
5992
6804
|
if (!meta) return void 0;
|
|
5993
|
-
const mapping = (
|
|
6805
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
5994
6806
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
5995
6807
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
5996
6808
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -5999,13 +6811,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
5999
6811
|
return resolveMetadataValue(meta, uiKey);
|
|
6000
6812
|
}
|
|
6001
6813
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6002
|
-
var
|
|
6814
|
+
var _a2;
|
|
6003
6815
|
const meta = item.metadata || {};
|
|
6004
6816
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6005
6817
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6006
6818
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6007
6819
|
const description = this.cleanProductDescription(
|
|
6008
|
-
(
|
|
6820
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6009
6821
|
);
|
|
6010
6822
|
if (name || this.isProductData(item)) {
|
|
6011
6823
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6113,10 +6925,10 @@ RULES:
|
|
|
6113
6925
|
}
|
|
6114
6926
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6115
6927
|
const items = sources.map((s, i) => {
|
|
6116
|
-
var
|
|
6928
|
+
var _a2, _b, _c, _d;
|
|
6117
6929
|
return {
|
|
6118
6930
|
index: i + 1,
|
|
6119
|
-
content: (_b = (
|
|
6931
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6120
6932
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6121
6933
|
score: (_d = s.score) != null ? _d : 0
|
|
6122
6934
|
};
|
|
@@ -6309,9 +7121,11 @@ var Pipeline = class {
|
|
|
6309
7121
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6310
7122
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6311
7123
|
this.initialised = false;
|
|
6312
|
-
|
|
7124
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7125
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7126
|
+
var _a2, _b, _c, _d, _e;
|
|
6313
7127
|
this.chunker = new DocumentChunker(
|
|
6314
|
-
(_b = (
|
|
7128
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6315
7129
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6316
7130
|
);
|
|
6317
7131
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6327,7 +7141,7 @@ var Pipeline = class {
|
|
|
6327
7141
|
return this.initialised ? this.llmProvider : void 0;
|
|
6328
7142
|
}
|
|
6329
7143
|
async initialize() {
|
|
6330
|
-
var
|
|
7144
|
+
var _a2, _b, _c, _d;
|
|
6331
7145
|
if (this.initialised) return;
|
|
6332
7146
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6333
7147
|
|
|
@@ -6370,12 +7184,47 @@ var Pipeline = class {
|
|
|
6370
7184
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6371
7185
|
}
|
|
6372
7186
|
await this.vectorDB.initialize();
|
|
6373
|
-
if (((
|
|
7187
|
+
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) {
|
|
7188
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7189
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7190
|
+
llmProvider: this.llmProvider,
|
|
7191
|
+
mcpRegistry: this.mcpRegistry,
|
|
7192
|
+
documentSearch: async (query) => {
|
|
7193
|
+
return this.runNormalQuery(query);
|
|
7194
|
+
}
|
|
7195
|
+
});
|
|
6374
7196
|
this.agent = new LangChainAgent(this, this.config);
|
|
6375
7197
|
await this.agent.initialize(this.llmProvider);
|
|
6376
7198
|
}
|
|
7199
|
+
if ((_d = (_c = this.config.rag) == null ? void 0 : _c.cag) == null ? void 0 : _d.enabled) {
|
|
7200
|
+
await this.loadColdContext(this.config.projectId);
|
|
7201
|
+
}
|
|
6377
7202
|
this.initialised = true;
|
|
6378
7203
|
}
|
|
7204
|
+
async loadColdContext(ns) {
|
|
7205
|
+
var _a2, _b;
|
|
7206
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7207
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7208
|
+
try {
|
|
7209
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7210
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7211
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7212
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7213
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7214
|
+
if (coldMatches.length > 0) {
|
|
7215
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7216
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7217
|
+
this.coldContexts.set(ns, formatted);
|
|
7218
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7219
|
+
} else {
|
|
7220
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7221
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7222
|
+
}
|
|
7223
|
+
} catch (err) {
|
|
7224
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7225
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7226
|
+
}
|
|
7227
|
+
}
|
|
6379
7228
|
/**
|
|
6380
7229
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6381
7230
|
*/
|
|
@@ -6407,12 +7256,12 @@ var Pipeline = class {
|
|
|
6407
7256
|
}
|
|
6408
7257
|
/** Step 1: Chunk the document content. */
|
|
6409
7258
|
async prepareChunks(doc) {
|
|
6410
|
-
var
|
|
7259
|
+
var _a2, _b;
|
|
6411
7260
|
if (this.llamaIngestor) {
|
|
6412
7261
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6413
7262
|
docId: doc.docId,
|
|
6414
7263
|
metadata: doc.metadata,
|
|
6415
|
-
chunkSize: (
|
|
7264
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6416
7265
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6417
7266
|
});
|
|
6418
7267
|
}
|
|
@@ -6483,12 +7332,37 @@ var Pipeline = class {
|
|
|
6483
7332
|
extractionOptions
|
|
6484
7333
|
);
|
|
6485
7334
|
}
|
|
7335
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7336
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7337
|
+
let reply = "";
|
|
7338
|
+
let sources = [];
|
|
7339
|
+
try {
|
|
7340
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7341
|
+
const chunk = temp.value;
|
|
7342
|
+
if (typeof chunk === "string") {
|
|
7343
|
+
reply += chunk;
|
|
7344
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7345
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7346
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7347
|
+
}
|
|
7348
|
+
}
|
|
7349
|
+
} catch (temp) {
|
|
7350
|
+
error = [temp];
|
|
7351
|
+
} finally {
|
|
7352
|
+
try {
|
|
7353
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7354
|
+
} finally {
|
|
7355
|
+
if (error)
|
|
7356
|
+
throw error[0];
|
|
7357
|
+
}
|
|
7358
|
+
}
|
|
7359
|
+
return { reply, sources };
|
|
7360
|
+
}
|
|
6486
7361
|
async ask(question, history = [], namespace) {
|
|
6487
|
-
var
|
|
7362
|
+
var _a2, _b;
|
|
6488
7363
|
await this.initialize();
|
|
6489
|
-
if (((
|
|
6490
|
-
|
|
6491
|
-
return { reply: agentReply, sources: [] };
|
|
7364
|
+
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) {
|
|
7365
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6492
7366
|
}
|
|
6493
7367
|
const stream = this.askStream(question, history, namespace);
|
|
6494
7368
|
let reply = "";
|
|
@@ -6508,17 +7382,58 @@ var Pipeline = class {
|
|
|
6508
7382
|
if ("trace" in chunk) trace = chunk.trace;
|
|
6509
7383
|
}
|
|
6510
7384
|
}
|
|
6511
|
-
} catch (temp) {
|
|
6512
|
-
error = [temp];
|
|
6513
|
-
} finally {
|
|
7385
|
+
} catch (temp) {
|
|
7386
|
+
error = [temp];
|
|
7387
|
+
} finally {
|
|
7388
|
+
try {
|
|
7389
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7390
|
+
} finally {
|
|
7391
|
+
if (error)
|
|
7392
|
+
throw error[0];
|
|
7393
|
+
}
|
|
7394
|
+
}
|
|
7395
|
+
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7396
|
+
}
|
|
7397
|
+
askStream(_0) {
|
|
7398
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7399
|
+
var _a2, _b;
|
|
7400
|
+
yield new __await(this.initialize());
|
|
7401
|
+
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) {
|
|
7402
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7403
|
+
try {
|
|
7404
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7405
|
+
const chunk = temp.value;
|
|
7406
|
+
yield chunk;
|
|
7407
|
+
}
|
|
7408
|
+
} catch (temp) {
|
|
7409
|
+
error = [temp];
|
|
7410
|
+
} finally {
|
|
7411
|
+
try {
|
|
7412
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7413
|
+
} finally {
|
|
7414
|
+
if (error)
|
|
7415
|
+
throw error[0];
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7418
|
+
return;
|
|
7419
|
+
}
|
|
7420
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
6514
7421
|
try {
|
|
6515
|
-
|
|
7422
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7423
|
+
const chunk = temp2.value;
|
|
7424
|
+
yield chunk;
|
|
7425
|
+
}
|
|
7426
|
+
} catch (temp2) {
|
|
7427
|
+
error2 = [temp2];
|
|
6516
7428
|
} finally {
|
|
6517
|
-
|
|
6518
|
-
|
|
7429
|
+
try {
|
|
7430
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7431
|
+
} finally {
|
|
7432
|
+
if (error2)
|
|
7433
|
+
throw error2[0];
|
|
7434
|
+
}
|
|
6519
7435
|
}
|
|
6520
|
-
}
|
|
6521
|
-
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7436
|
+
});
|
|
6522
7437
|
}
|
|
6523
7438
|
/**
|
|
6524
7439
|
* High-performance streaming RAG flow.
|
|
@@ -6530,12 +7445,12 @@ var Pipeline = class {
|
|
|
6530
7445
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6531
7446
|
* - SchemaMapper.train runs while answer generation streams
|
|
6532
7447
|
*/
|
|
6533
|
-
|
|
7448
|
+
askStreamInternal(_0) {
|
|
6534
7449
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6535
|
-
var
|
|
7450
|
+
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;
|
|
6536
7451
|
yield new __await(this.initialize());
|
|
6537
7452
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6538
|
-
const topK = (_b = (
|
|
7453
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6539
7454
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6540
7455
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6541
7456
|
const requestStart = performance.now();
|
|
@@ -6548,20 +7463,21 @@ var Pipeline = class {
|
|
|
6548
7463
|
}
|
|
6549
7464
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6550
7465
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6551
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7466
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6552
7467
|
if (numericPredicates.length > 0) {
|
|
6553
7468
|
filter.__numericPredicates = numericPredicates;
|
|
6554
7469
|
}
|
|
6555
7470
|
const embedStart = performance.now();
|
|
6556
7471
|
const cacheKey = `${ns}::${searchQuery}`;
|
|
6557
7472
|
const cachedVector = this.embeddingCache.get(cacheKey);
|
|
6558
|
-
const
|
|
7473
|
+
const arch = (_h = this.config.rag) == null ? void 0 : _h.architecture;
|
|
7474
|
+
const useGraph = arch !== "naive" && arch !== "retrieve-and-rerank" && this.graphDB && ((_i = this.config.rag) == null ? void 0 : _i.useGraphRetrieval);
|
|
6559
7475
|
const [strategyResult, embeddedVector] = yield new __await(Promise.all([
|
|
6560
7476
|
QueryProcessor.determineRetrievalStrategy(
|
|
6561
7477
|
searchQuery,
|
|
6562
7478
|
useGraph ? this.llmRouter.get("fast") : void 0,
|
|
6563
|
-
(
|
|
6564
|
-
(
|
|
7479
|
+
(_j = this.config.rag) == null ? void 0 : _j.graphKeywords,
|
|
7480
|
+
(_k = this.config.rag) == null ? void 0 : _k.vectorKeywords
|
|
6565
7481
|
),
|
|
6566
7482
|
// Embed immediately regardless of strategy — costs nothing if cached.
|
|
6567
7483
|
// If strategy turns out to be 'graph'-only we just won't use the vector.
|
|
@@ -6571,7 +7487,7 @@ var Pipeline = class {
|
|
|
6571
7487
|
if (!cachedVector && queryVector.length > 0) {
|
|
6572
7488
|
this.embeddingCache.set(cacheKey, queryVector);
|
|
6573
7489
|
}
|
|
6574
|
-
const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((
|
|
7490
|
+
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;
|
|
6575
7491
|
const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
|
|
6576
7492
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
6577
7493
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
@@ -6584,7 +7500,8 @@ var Pipeline = class {
|
|
|
6584
7500
|
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
6585
7501
|
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
|
|
6586
7502
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
6587
|
-
|
|
7503
|
+
const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
|
|
7504
|
+
if (!hasNumericPredicates && useReranking) {
|
|
6588
7505
|
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
6589
7506
|
} else if (!wantsExhaustiveList) {
|
|
6590
7507
|
fullSources = fullSources.slice(0, topK);
|
|
@@ -6614,6 +7531,32 @@ ${graphContext}
|
|
|
6614
7531
|
VECTOR CONTEXT:
|
|
6615
7532
|
${context}`;
|
|
6616
7533
|
}
|
|
7534
|
+
if ((_o = (_n = this.config.rag) == null ? void 0 : _n.cag) == null ? void 0 : _o.enabled) {
|
|
7535
|
+
if (!this.coldContexts.has(ns)) {
|
|
7536
|
+
yield new __await(this.loadColdContext(ns));
|
|
7537
|
+
}
|
|
7538
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7539
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7540
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7541
|
+
${coldContext}
|
|
7542
|
+
|
|
7543
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7544
|
+
${context}`;
|
|
7545
|
+
}
|
|
7546
|
+
}
|
|
7547
|
+
yield {
|
|
7548
|
+
reply: "",
|
|
7549
|
+
sources: sources.map((s) => {
|
|
7550
|
+
var _a3;
|
|
7551
|
+
return {
|
|
7552
|
+
id: s.id,
|
|
7553
|
+
score: s.score,
|
|
7554
|
+
content: s.content,
|
|
7555
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7556
|
+
namespace: ns
|
|
7557
|
+
};
|
|
7558
|
+
})
|
|
7559
|
+
};
|
|
6617
7560
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6618
7561
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6619
7562
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6641,10 +7584,10 @@ ${context}`;
|
|
|
6641
7584
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6642
7585
|
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.)";
|
|
6643
7586
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6644
|
-
const isNativeThinking = isClaude37 && (((
|
|
7587
|
+
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);
|
|
6645
7588
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6646
7589
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6647
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7590
|
+
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);
|
|
6648
7591
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6649
7592
|
if (isSimulatedThinking) {
|
|
6650
7593
|
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.`)";
|
|
@@ -6652,7 +7595,7 @@ ${context}`;
|
|
|
6652
7595
|
const hardenedHistory = [...history];
|
|
6653
7596
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6654
7597
|
const messages = [...hardenedHistory, userQuestion];
|
|
6655
|
-
const systemPrompt = (
|
|
7598
|
+
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
6656
7599
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6657
7600
|
let fullReply = "";
|
|
6658
7601
|
let thinkingText = "";
|
|
@@ -6763,7 +7706,7 @@ ${context}`;
|
|
|
6763
7706
|
}
|
|
6764
7707
|
yield fullReply;
|
|
6765
7708
|
}
|
|
6766
|
-
const runHallucination = ((
|
|
7709
|
+
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;
|
|
6767
7710
|
if (runHallucination) {
|
|
6768
7711
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6769
7712
|
}
|
|
@@ -6772,7 +7715,7 @@ ${context}`;
|
|
|
6772
7715
|
const latency = {
|
|
6773
7716
|
embedMs: Math.round(embedMs),
|
|
6774
7717
|
retrieveMs: Math.round(retrieveMs),
|
|
6775
|
-
rerankMs: ((
|
|
7718
|
+
rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
|
|
6776
7719
|
generateMs: Math.round(generateMs),
|
|
6777
7720
|
totalMs: Math.round(totalMs)
|
|
6778
7721
|
};
|
|
@@ -6785,33 +7728,63 @@ ${context}`;
|
|
|
6785
7728
|
totalTokens: promptTokens + completionTokens,
|
|
6786
7729
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6787
7730
|
};
|
|
7731
|
+
const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
|
|
6788
7732
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6789
7733
|
uiTransformationPromise,
|
|
6790
|
-
hallucinationScoringPromise
|
|
7734
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6791
7735
|
]));
|
|
6792
|
-
const
|
|
7736
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6793
7737
|
requestId,
|
|
6794
7738
|
query: question,
|
|
6795
7739
|
rewrittenQuery,
|
|
6796
7740
|
systemPrompt,
|
|
6797
7741
|
userPrompt: question + finalRestrictionSuffix,
|
|
6798
7742
|
chunks: sources.map((s) => {
|
|
6799
|
-
var
|
|
7743
|
+
var _a3;
|
|
6800
7744
|
return {
|
|
6801
7745
|
id: s.id,
|
|
6802
7746
|
score: s.score,
|
|
6803
7747
|
content: s.content,
|
|
6804
|
-
metadata: (
|
|
7748
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6805
7749
|
namespace: ns
|
|
6806
7750
|
};
|
|
6807
7751
|
}),
|
|
6808
7752
|
latency,
|
|
6809
7753
|
tokens,
|
|
6810
7754
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6811
|
-
},
|
|
6812
|
-
hallucinationScore:
|
|
6813
|
-
hallucinationReason:
|
|
7755
|
+
}, hScore ? {
|
|
7756
|
+
hallucinationScore: hScore.score,
|
|
7757
|
+
hallucinationReason: hScore.reason
|
|
6814
7758
|
} : {});
|
|
7759
|
+
const trace = buildTrace(hallucinationResult);
|
|
7760
|
+
if ((_A = this.config.telemetry) == null ? void 0 : _A.enabled) {
|
|
7761
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7762
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7763
|
+
(async () => {
|
|
7764
|
+
try {
|
|
7765
|
+
let finalTrace = trace;
|
|
7766
|
+
if (!awaitHallucination && runHallucination) {
|
|
7767
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7768
|
+
if (backgroundScoreResult) {
|
|
7769
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7772
|
+
await fetch(absoluteUrl, {
|
|
7773
|
+
method: "POST",
|
|
7774
|
+
headers: {
|
|
7775
|
+
"Content-Type": "application/json"
|
|
7776
|
+
},
|
|
7777
|
+
body: JSON.stringify({
|
|
7778
|
+
trace: finalTrace,
|
|
7779
|
+
licenseKey: this.config.licenseKey,
|
|
7780
|
+
projectId: ns
|
|
7781
|
+
})
|
|
7782
|
+
});
|
|
7783
|
+
} catch (err) {
|
|
7784
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
7785
|
+
}
|
|
7786
|
+
})();
|
|
7787
|
+
}
|
|
6815
7788
|
yield {
|
|
6816
7789
|
reply: "",
|
|
6817
7790
|
sources,
|
|
@@ -6831,7 +7804,7 @@ ${context}`;
|
|
|
6831
7804
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6832
7805
|
*/
|
|
6833
7806
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6834
|
-
var
|
|
7807
|
+
var _a2;
|
|
6835
7808
|
if (!sources || sources.length === 0) {
|
|
6836
7809
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6837
7810
|
}
|
|
@@ -6845,7 +7818,7 @@ ${context}`;
|
|
|
6845
7818
|
);
|
|
6846
7819
|
}
|
|
6847
7820
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6848
|
-
const disableLlmUiTransform = ((
|
|
7821
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6849
7822
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6850
7823
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6851
7824
|
}
|
|
@@ -6863,9 +7836,9 @@ ${context}`;
|
|
|
6863
7836
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6864
7837
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6865
7838
|
})).sort((a, b) => {
|
|
6866
|
-
var
|
|
7839
|
+
var _a2, _b;
|
|
6867
7840
|
const primary = predicates[0];
|
|
6868
|
-
const aValue = (
|
|
7841
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6869
7842
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6870
7843
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6871
7844
|
});
|
|
@@ -6937,8 +7910,8 @@ ${context}`;
|
|
|
6937
7910
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6938
7911
|
}
|
|
6939
7912
|
async retrieve(query, options) {
|
|
6940
|
-
var
|
|
6941
|
-
const ns = (
|
|
7913
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
7914
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
6942
7915
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6943
7916
|
const cacheKey = `${ns}::${query}`;
|
|
6944
7917
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -6970,7 +7943,7 @@ ${context}`;
|
|
|
6970
7943
|
) : [];
|
|
6971
7944
|
const resolvedSources = [];
|
|
6972
7945
|
for (const source of sources) {
|
|
6973
|
-
const parentId = (
|
|
7946
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
6974
7947
|
if (parentId) {
|
|
6975
7948
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6976
7949
|
resolvedSources.push(source);
|
|
@@ -7148,14 +8121,228 @@ var ProviderHealthCheck = class {
|
|
|
7148
8121
|
}
|
|
7149
8122
|
};
|
|
7150
8123
|
|
|
8124
|
+
// src/core/LicenseVerifier.ts
|
|
8125
|
+
import * as crypto2 from "crypto";
|
|
8126
|
+
var LicenseVerifier = class {
|
|
8127
|
+
/**
|
|
8128
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
8129
|
+
*
|
|
8130
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
8131
|
+
* @param currentProjectId - Project namespace ID.
|
|
8132
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
8133
|
+
*/
|
|
8134
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
8135
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
8136
|
+
const now = Date.now();
|
|
8137
|
+
if (licenseKey) {
|
|
8138
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
8139
|
+
const cached = this.cache.get(cacheKey);
|
|
8140
|
+
if (cached && now - cached.cachedAt < this.CACHE_TTL_MS) {
|
|
8141
|
+
const currentTimestampSec = Math.floor(now / 1e3);
|
|
8142
|
+
if (cached.payload.expiresAt && currentTimestampSec > cached.payload.expiresAt) {
|
|
8143
|
+
this.cache.delete(cacheKey);
|
|
8144
|
+
} else {
|
|
8145
|
+
return cached.payload;
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
}
|
|
8149
|
+
if (!licenseKey) {
|
|
8150
|
+
if (isProduction) {
|
|
8151
|
+
throw new ConfigurationException(
|
|
8152
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
8153
|
+
);
|
|
8154
|
+
}
|
|
8155
|
+
console.warn(
|
|
8156
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
8157
|
+
);
|
|
8158
|
+
return {
|
|
8159
|
+
projectId: currentProjectId,
|
|
8160
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
8161
|
+
// Valid for 24h
|
|
8162
|
+
tier: "hobby"
|
|
8163
|
+
};
|
|
8164
|
+
}
|
|
8165
|
+
try {
|
|
8166
|
+
const parts = licenseKey.split(".");
|
|
8167
|
+
if (parts.length !== 3) {
|
|
8168
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
8169
|
+
}
|
|
8170
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
8171
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
8172
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
8173
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
8174
|
+
const data = Buffer.from(dataToVerify);
|
|
8175
|
+
const isValid = crypto2.verify(
|
|
8176
|
+
"sha256",
|
|
8177
|
+
data,
|
|
8178
|
+
publicKey,
|
|
8179
|
+
signature
|
|
8180
|
+
);
|
|
8181
|
+
if (!isValid) {
|
|
8182
|
+
throw new Error("Signature verification failed.");
|
|
8183
|
+
}
|
|
8184
|
+
const payload = JSON.parse(
|
|
8185
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8186
|
+
);
|
|
8187
|
+
if (!payload.projectId) {
|
|
8188
|
+
throw new Error('License payload is missing "projectId".');
|
|
8189
|
+
}
|
|
8190
|
+
if (payload.projectId !== currentProjectId) {
|
|
8191
|
+
throw new Error(
|
|
8192
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
8193
|
+
);
|
|
8194
|
+
}
|
|
8195
|
+
if (!payload.expiresAt) {
|
|
8196
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
8197
|
+
}
|
|
8198
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
8199
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
8200
|
+
throw new Error(
|
|
8201
|
+
`License key has expired. Expiration: ${new Date(
|
|
8202
|
+
payload.expiresAt * 1e3
|
|
8203
|
+
).toDateString()}`
|
|
8204
|
+
);
|
|
8205
|
+
}
|
|
8206
|
+
if (isProduction && provider) {
|
|
8207
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8208
|
+
const normalizedProvider = provider.toLowerCase();
|
|
8209
|
+
if (tier === "hobby") {
|
|
8210
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
8211
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
8212
|
+
throw new Error(
|
|
8213
|
+
`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.`
|
|
8214
|
+
);
|
|
8215
|
+
}
|
|
8216
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
8217
|
+
const allowedPro = [
|
|
8218
|
+
"postgresql",
|
|
8219
|
+
"pgvector",
|
|
8220
|
+
"supabase",
|
|
8221
|
+
"pinecone",
|
|
8222
|
+
"qdrant",
|
|
8223
|
+
"mongodb",
|
|
8224
|
+
"milvus",
|
|
8225
|
+
"chroma",
|
|
8226
|
+
"chromadb"
|
|
8227
|
+
];
|
|
8228
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
8229
|
+
throw new Error(
|
|
8230
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
8231
|
+
);
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8234
|
+
}
|
|
8235
|
+
if (licenseKey) {
|
|
8236
|
+
const cacheKey = `${licenseKey}:${currentProjectId}:${provider || ""}:${publicKeyOverride || ""}`;
|
|
8237
|
+
this.cache.set(cacheKey, { payload, cachedAt: now });
|
|
8238
|
+
}
|
|
8239
|
+
return payload;
|
|
8240
|
+
} catch (err) {
|
|
8241
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8242
|
+
throw new ConfigurationException(
|
|
8243
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
8244
|
+
);
|
|
8245
|
+
}
|
|
8246
|
+
}
|
|
8247
|
+
static async verifyIP(licenseKey) {
|
|
8248
|
+
if (!licenseKey) return;
|
|
8249
|
+
try {
|
|
8250
|
+
const parts = licenseKey.split(".");
|
|
8251
|
+
if (parts.length !== 3) return;
|
|
8252
|
+
const [, payloadB64] = parts;
|
|
8253
|
+
const payload = JSON.parse(
|
|
8254
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8255
|
+
);
|
|
8256
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8257
|
+
if (tier === "enterprise" || tier === "custom") {
|
|
8258
|
+
return;
|
|
8259
|
+
}
|
|
8260
|
+
if (payload.ipv4 || payload.ipv6) {
|
|
8261
|
+
let currentIpv4 = "";
|
|
8262
|
+
let currentIpv6 = "";
|
|
8263
|
+
try {
|
|
8264
|
+
const res = await fetch("https://api4.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
8265
|
+
const data = await res.json();
|
|
8266
|
+
currentIpv4 = data.ip;
|
|
8267
|
+
} catch (e) {
|
|
8268
|
+
}
|
|
8269
|
+
try {
|
|
8270
|
+
const res = await fetch("https://api6.ipify.org?format=json", { signal: AbortSignal.timeout(3e3) });
|
|
8271
|
+
const data = await res.json();
|
|
8272
|
+
currentIpv6 = data.ip;
|
|
8273
|
+
} catch (e) {
|
|
8274
|
+
}
|
|
8275
|
+
const localIps = [];
|
|
8276
|
+
try {
|
|
8277
|
+
const osModule = __require("os");
|
|
8278
|
+
const interfaces = osModule.networkInterfaces();
|
|
8279
|
+
for (const name of Object.keys(interfaces)) {
|
|
8280
|
+
for (const iface of interfaces[name] || []) {
|
|
8281
|
+
if (!iface.internal) {
|
|
8282
|
+
localIps.push(iface.address);
|
|
8283
|
+
}
|
|
8284
|
+
}
|
|
8285
|
+
}
|
|
8286
|
+
} catch (e) {
|
|
8287
|
+
}
|
|
8288
|
+
const isIpv4Match = payload.ipv4 && (currentIpv4 === payload.ipv4 || localIps.includes(payload.ipv4));
|
|
8289
|
+
const isIpv6Match = payload.ipv6 && (currentIpv6 === payload.ipv6 || localIps.includes(payload.ipv6));
|
|
8290
|
+
if (payload.ipv4 && payload.ipv6) {
|
|
8291
|
+
if (!isIpv4Match && !isIpv6Match) {
|
|
8292
|
+
throw new Error(
|
|
8293
|
+
`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.`
|
|
8294
|
+
);
|
|
8295
|
+
}
|
|
8296
|
+
} else if (payload.ipv4 && !isIpv4Match) {
|
|
8297
|
+
throw new Error(
|
|
8298
|
+
`License key access restricted. This license key was created for a different system (authorized IPv4: ${payload.ipv4}) and cannot be used on this machine.`
|
|
8299
|
+
);
|
|
8300
|
+
} else if (payload.ipv6 && !isIpv6Match) {
|
|
8301
|
+
throw new Error(
|
|
8302
|
+
`License key access restricted. This license key was created for a different system (authorized IPv6: ${payload.ipv6}) and cannot be used on this machine.`
|
|
8303
|
+
);
|
|
8304
|
+
}
|
|
8305
|
+
}
|
|
8306
|
+
} catch (err) {
|
|
8307
|
+
if (err.message.includes("License key access restricted")) {
|
|
8308
|
+
throw new ConfigurationException(`[Retrivora SDK] ${err.message}`);
|
|
8309
|
+
}
|
|
8310
|
+
}
|
|
8311
|
+
}
|
|
8312
|
+
};
|
|
8313
|
+
// A simple in-memory cache to save CPU overhead of cryptographic signature checks.
|
|
8314
|
+
LicenseVerifier.cache = /* @__PURE__ */ new Map();
|
|
8315
|
+
LicenseVerifier.CACHE_TTL_MS = 60 * 1e3;
|
|
8316
|
+
// Cache verified license for 60 seconds
|
|
8317
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
8318
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
8319
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
8320
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
8321
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
8322
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
8323
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
8324
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
8325
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
8326
|
+
MwIDAQAB
|
|
8327
|
+
-----END PUBLIC KEY-----`;
|
|
8328
|
+
|
|
7151
8329
|
// src/core/VectorPlugin.ts
|
|
7152
8330
|
var VectorPlugin = class {
|
|
7153
8331
|
constructor(hostConfig) {
|
|
7154
|
-
|
|
7155
|
-
this.
|
|
8332
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8333
|
+
this.config = resolvedConfig;
|
|
8334
|
+
this.validationPromise = (async () => {
|
|
8335
|
+
var _a2;
|
|
8336
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8337
|
+
LicenseVerifier.verify(
|
|
8338
|
+
resolvedConfig.licenseKey,
|
|
8339
|
+
resolvedConfig.projectId,
|
|
8340
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8341
|
+
);
|
|
8342
|
+
})();
|
|
7156
8343
|
this.validationPromise.catch(() => {
|
|
7157
8344
|
});
|
|
7158
|
-
this.pipeline = new Pipeline(
|
|
8345
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7159
8346
|
}
|
|
7160
8347
|
/**
|
|
7161
8348
|
* Get the current resolved configuration.
|
|
@@ -7284,8 +8471,8 @@ var DocumentParser = class {
|
|
|
7284
8471
|
* Extract text from a File or Buffer based on its type.
|
|
7285
8472
|
*/
|
|
7286
8473
|
static async parse(file, fileName, mimeType) {
|
|
7287
|
-
var
|
|
7288
|
-
const extension = (
|
|
8474
|
+
var _a2;
|
|
8475
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7289
8476
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7290
8477
|
return this.readAsText(file);
|
|
7291
8478
|
}
|
|
@@ -7337,7 +8524,496 @@ var DocumentParser = class {
|
|
|
7337
8524
|
}
|
|
7338
8525
|
};
|
|
7339
8526
|
|
|
8527
|
+
// src/core/DatabaseStorage.ts
|
|
8528
|
+
import * as fs from "fs";
|
|
8529
|
+
import * as path from "path";
|
|
8530
|
+
var DatabaseStorage = class {
|
|
8531
|
+
constructor(config) {
|
|
8532
|
+
// Dynamic PG Pool
|
|
8533
|
+
this.pgPool = null;
|
|
8534
|
+
// Dynamic MongoDB Client
|
|
8535
|
+
this.mongoClient = null;
|
|
8536
|
+
this.mongoDbName = "";
|
|
8537
|
+
// Filesystem fallback configuration
|
|
8538
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8539
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8540
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8541
|
+
var _a2, _b, _c, _d, _e;
|
|
8542
|
+
this.config = config;
|
|
8543
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8544
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8545
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8546
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8547
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8548
|
+
}
|
|
8549
|
+
/**
|
|
8550
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8551
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8552
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8553
|
+
*/
|
|
8554
|
+
checkPremiumSubscription() {
|
|
8555
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8556
|
+
return;
|
|
8557
|
+
}
|
|
8558
|
+
if (!this.config.licenseKey) {
|
|
8559
|
+
throw new Error(
|
|
8560
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8561
|
+
);
|
|
8562
|
+
}
|
|
8563
|
+
try {
|
|
8564
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8565
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8566
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8567
|
+
throw new Error(
|
|
8568
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8569
|
+
);
|
|
8570
|
+
}
|
|
8571
|
+
} catch (err) {
|
|
8572
|
+
throw new Error(
|
|
8573
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8574
|
+
);
|
|
8575
|
+
}
|
|
8576
|
+
}
|
|
8577
|
+
checkHistoryEnabled() {
|
|
8578
|
+
var _a2, _b;
|
|
8579
|
+
this.checkPremiumSubscription();
|
|
8580
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8581
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8584
|
+
checkFeedbackEnabled() {
|
|
8585
|
+
var _a2, _b;
|
|
8586
|
+
this.checkPremiumSubscription();
|
|
8587
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8588
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8589
|
+
}
|
|
8590
|
+
}
|
|
8591
|
+
async getPGPool() {
|
|
8592
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8593
|
+
const _g2 = global;
|
|
8594
|
+
if (_g2[globalKey]) {
|
|
8595
|
+
this.pgPool = _g2[globalKey];
|
|
8596
|
+
return this.pgPool;
|
|
8597
|
+
}
|
|
8598
|
+
const opts = this.config.vectorDb.options;
|
|
8599
|
+
if (!opts.connectionString) {
|
|
8600
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8601
|
+
}
|
|
8602
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8603
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8604
|
+
_g2[globalKey] = this.pgPool;
|
|
8605
|
+
const client = await this.pgPool.connect();
|
|
8606
|
+
try {
|
|
8607
|
+
await client.query(`
|
|
8608
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8609
|
+
id TEXT PRIMARY KEY,
|
|
8610
|
+
session_id TEXT NOT NULL,
|
|
8611
|
+
role TEXT NOT NULL,
|
|
8612
|
+
content TEXT NOT NULL,
|
|
8613
|
+
sources JSONB,
|
|
8614
|
+
ui_transformation JSONB,
|
|
8615
|
+
trace JSONB,
|
|
8616
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8617
|
+
)
|
|
8618
|
+
`);
|
|
8619
|
+
await client.query(`
|
|
8620
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8621
|
+
id TEXT PRIMARY KEY,
|
|
8622
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8623
|
+
session_id TEXT NOT NULL,
|
|
8624
|
+
rating TEXT NOT NULL,
|
|
8625
|
+
comment TEXT,
|
|
8626
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8627
|
+
)
|
|
8628
|
+
`);
|
|
8629
|
+
} finally {
|
|
8630
|
+
client.release();
|
|
8631
|
+
}
|
|
8632
|
+
return this.pgPool;
|
|
8633
|
+
}
|
|
8634
|
+
async getMongoClient() {
|
|
8635
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8636
|
+
const _g2 = global;
|
|
8637
|
+
if (_g2[globalKey]) {
|
|
8638
|
+
this.mongoClient = _g2[globalKey];
|
|
8639
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8640
|
+
return this.mongoClient;
|
|
8641
|
+
}
|
|
8642
|
+
const opts = this.config.vectorDb.options;
|
|
8643
|
+
if (!opts.uri || !opts.database) {
|
|
8644
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8645
|
+
}
|
|
8646
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8647
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8648
|
+
await this.mongoClient.connect();
|
|
8649
|
+
_g2[globalKey] = this.mongoClient;
|
|
8650
|
+
this.mongoDbName = opts.database;
|
|
8651
|
+
return this.mongoClient;
|
|
8652
|
+
}
|
|
8653
|
+
getMongoDb() {
|
|
8654
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8655
|
+
}
|
|
8656
|
+
// Helper for FS fallback reads
|
|
8657
|
+
readLocalFile(filePath) {
|
|
8658
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8659
|
+
try {
|
|
8660
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8661
|
+
return JSON.parse(raw) || [];
|
|
8662
|
+
} catch (e) {
|
|
8663
|
+
return [];
|
|
8664
|
+
}
|
|
8665
|
+
}
|
|
8666
|
+
// Helper for FS fallback writes
|
|
8667
|
+
writeLocalFile(filePath, data) {
|
|
8668
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8669
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8670
|
+
}
|
|
8671
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8672
|
+
}
|
|
8673
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8674
|
+
async saveMessage(sessionId, message) {
|
|
8675
|
+
this.checkHistoryEnabled();
|
|
8676
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8677
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8678
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8679
|
+
const pool = await this.getPGPool();
|
|
8680
|
+
await pool.query(
|
|
8681
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8682
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8683
|
+
ON CONFLICT (id) DO UPDATE
|
|
8684
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8685
|
+
[
|
|
8686
|
+
msgId,
|
|
8687
|
+
sessionId,
|
|
8688
|
+
message.role,
|
|
8689
|
+
message.content,
|
|
8690
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
8691
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
8692
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
8693
|
+
createdAt
|
|
8694
|
+
]
|
|
8695
|
+
);
|
|
8696
|
+
} else if (this.provider === "mongodb") {
|
|
8697
|
+
await this.getMongoClient();
|
|
8698
|
+
const db = this.getMongoDb();
|
|
8699
|
+
const col = db.collection(this.historyTableName);
|
|
8700
|
+
await col.updateOne(
|
|
8701
|
+
{ id: msgId },
|
|
8702
|
+
{
|
|
8703
|
+
$set: {
|
|
8704
|
+
id: msgId,
|
|
8705
|
+
session_id: sessionId,
|
|
8706
|
+
role: message.role,
|
|
8707
|
+
content: message.content,
|
|
8708
|
+
sources: message.sources || null,
|
|
8709
|
+
ui_transformation: message.uiTransformation || null,
|
|
8710
|
+
trace: message.trace || null,
|
|
8711
|
+
created_at: createdAt
|
|
8712
|
+
}
|
|
8713
|
+
},
|
|
8714
|
+
{ upsert: true }
|
|
8715
|
+
);
|
|
8716
|
+
} else {
|
|
8717
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8718
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
8719
|
+
const item = {
|
|
8720
|
+
id: msgId,
|
|
8721
|
+
session_id: sessionId,
|
|
8722
|
+
role: message.role,
|
|
8723
|
+
content: message.content,
|
|
8724
|
+
sources: message.sources || null,
|
|
8725
|
+
ui_transformation: message.uiTransformation || null,
|
|
8726
|
+
trace: message.trace || null,
|
|
8727
|
+
created_at: createdAt
|
|
8728
|
+
};
|
|
8729
|
+
if (index !== -1) {
|
|
8730
|
+
history[index] = item;
|
|
8731
|
+
} else {
|
|
8732
|
+
history.push(item);
|
|
8733
|
+
}
|
|
8734
|
+
this.writeLocalFile(this.historyFile, history);
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
async getHistory(sessionId) {
|
|
8738
|
+
this.checkHistoryEnabled();
|
|
8739
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8740
|
+
const pool = await this.getPGPool();
|
|
8741
|
+
const res = await pool.query(
|
|
8742
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
8743
|
+
FROM ${this.historyTableName}
|
|
8744
|
+
WHERE session_id = $1
|
|
8745
|
+
ORDER BY created_at ASC`,
|
|
8746
|
+
[sessionId]
|
|
8747
|
+
);
|
|
8748
|
+
return res.rows;
|
|
8749
|
+
} else if (this.provider === "mongodb") {
|
|
8750
|
+
await this.getMongoClient();
|
|
8751
|
+
const db = this.getMongoDb();
|
|
8752
|
+
const col = db.collection(this.historyTableName);
|
|
8753
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
8754
|
+
return items.map((item) => ({
|
|
8755
|
+
id: item.id,
|
|
8756
|
+
role: item.role,
|
|
8757
|
+
content: item.content,
|
|
8758
|
+
sources: item.sources,
|
|
8759
|
+
uiTransformation: item.ui_transformation,
|
|
8760
|
+
trace: item.trace,
|
|
8761
|
+
createdAt: item.created_at
|
|
8762
|
+
}));
|
|
8763
|
+
} else {
|
|
8764
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8765
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
8766
|
+
}
|
|
8767
|
+
}
|
|
8768
|
+
async clearHistory(sessionId) {
|
|
8769
|
+
this.checkHistoryEnabled();
|
|
8770
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8771
|
+
const pool = await this.getPGPool();
|
|
8772
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
8773
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
8774
|
+
} else if (this.provider === "mongodb") {
|
|
8775
|
+
await this.getMongoClient();
|
|
8776
|
+
const db = this.getMongoDb();
|
|
8777
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
8778
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
8779
|
+
} else {
|
|
8780
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8781
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
8782
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
8783
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
8784
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
8785
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
8786
|
+
}
|
|
8787
|
+
}
|
|
8788
|
+
async listSessions() {
|
|
8789
|
+
this.checkHistoryEnabled();
|
|
8790
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8791
|
+
const pool = await this.getPGPool();
|
|
8792
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
8793
|
+
return res.rows.map((r) => r.session_id);
|
|
8794
|
+
} else if (this.provider === "mongodb") {
|
|
8795
|
+
await this.getMongoClient();
|
|
8796
|
+
const db = this.getMongoDb();
|
|
8797
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
8798
|
+
} else {
|
|
8799
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8800
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
8801
|
+
return Array.from(sessions);
|
|
8802
|
+
}
|
|
8803
|
+
}
|
|
8804
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
8805
|
+
async saveFeedback(feedback) {
|
|
8806
|
+
this.checkFeedbackEnabled();
|
|
8807
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8808
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8809
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8810
|
+
const pool = await this.getPGPool();
|
|
8811
|
+
await pool.query(
|
|
8812
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
8813
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
8814
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
8815
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
8816
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
8817
|
+
);
|
|
8818
|
+
} else if (this.provider === "mongodb") {
|
|
8819
|
+
await this.getMongoClient();
|
|
8820
|
+
const db = this.getMongoDb();
|
|
8821
|
+
const col = db.collection(this.feedbackTableName);
|
|
8822
|
+
await col.updateOne(
|
|
8823
|
+
{ message_id: feedback.messageId },
|
|
8824
|
+
{
|
|
8825
|
+
$set: {
|
|
8826
|
+
id,
|
|
8827
|
+
message_id: feedback.messageId,
|
|
8828
|
+
session_id: feedback.sessionId,
|
|
8829
|
+
rating: feedback.rating,
|
|
8830
|
+
comment: feedback.comment || null,
|
|
8831
|
+
created_at: createdAt
|
|
8832
|
+
}
|
|
8833
|
+
},
|
|
8834
|
+
{ upsert: true }
|
|
8835
|
+
);
|
|
8836
|
+
} else {
|
|
8837
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8838
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
8839
|
+
const item = {
|
|
8840
|
+
id,
|
|
8841
|
+
message_id: feedback.messageId,
|
|
8842
|
+
session_id: feedback.sessionId,
|
|
8843
|
+
rating: feedback.rating,
|
|
8844
|
+
comment: feedback.comment || null,
|
|
8845
|
+
created_at: createdAt
|
|
8846
|
+
};
|
|
8847
|
+
if (index !== -1) {
|
|
8848
|
+
list[index] = item;
|
|
8849
|
+
} else {
|
|
8850
|
+
list.push(item);
|
|
8851
|
+
}
|
|
8852
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
8853
|
+
}
|
|
8854
|
+
}
|
|
8855
|
+
async getFeedback(messageId) {
|
|
8856
|
+
this.checkFeedbackEnabled();
|
|
8857
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8858
|
+
const pool = await this.getPGPool();
|
|
8859
|
+
const res = await pool.query(
|
|
8860
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8861
|
+
FROM ${this.feedbackTableName}
|
|
8862
|
+
WHERE message_id = $1`,
|
|
8863
|
+
[messageId]
|
|
8864
|
+
);
|
|
8865
|
+
return res.rows[0] || null;
|
|
8866
|
+
} else if (this.provider === "mongodb") {
|
|
8867
|
+
await this.getMongoClient();
|
|
8868
|
+
const db = this.getMongoDb();
|
|
8869
|
+
const col = db.collection(this.feedbackTableName);
|
|
8870
|
+
const item = await col.findOne({ message_id: messageId });
|
|
8871
|
+
if (!item) return null;
|
|
8872
|
+
return {
|
|
8873
|
+
id: item.id,
|
|
8874
|
+
messageId: item.message_id,
|
|
8875
|
+
sessionId: item.session_id,
|
|
8876
|
+
rating: item.rating,
|
|
8877
|
+
comment: item.comment,
|
|
8878
|
+
createdAt: item.created_at
|
|
8879
|
+
};
|
|
8880
|
+
} else {
|
|
8881
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8882
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
8883
|
+
}
|
|
8884
|
+
}
|
|
8885
|
+
async listFeedback() {
|
|
8886
|
+
this.checkFeedbackEnabled();
|
|
8887
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8888
|
+
const pool = await this.getPGPool();
|
|
8889
|
+
const res = await pool.query(
|
|
8890
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8891
|
+
FROM ${this.feedbackTableName}
|
|
8892
|
+
ORDER BY created_at DESC`
|
|
8893
|
+
);
|
|
8894
|
+
return res.rows;
|
|
8895
|
+
} else if (this.provider === "mongodb") {
|
|
8896
|
+
await this.getMongoClient();
|
|
8897
|
+
const db = this.getMongoDb();
|
|
8898
|
+
const col = db.collection(this.feedbackTableName);
|
|
8899
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
8900
|
+
return items.map((item) => ({
|
|
8901
|
+
id: item.id,
|
|
8902
|
+
messageId: item.message_id,
|
|
8903
|
+
sessionId: item.session_id,
|
|
8904
|
+
rating: item.rating,
|
|
8905
|
+
comment: item.comment,
|
|
8906
|
+
createdAt: item.created_at
|
|
8907
|
+
}));
|
|
8908
|
+
} else {
|
|
8909
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8910
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
async disconnect() {
|
|
8914
|
+
if (this.pgPool) {
|
|
8915
|
+
await this.pgPool.end();
|
|
8916
|
+
this.pgPool = null;
|
|
8917
|
+
}
|
|
8918
|
+
if (this.mongoClient) {
|
|
8919
|
+
await this.mongoClient.close();
|
|
8920
|
+
this.mongoClient = null;
|
|
8921
|
+
}
|
|
8922
|
+
}
|
|
8923
|
+
};
|
|
8924
|
+
|
|
7340
8925
|
// src/handlers/index.ts
|
|
8926
|
+
async function checkAuth(req, onAuthorize) {
|
|
8927
|
+
if (!onAuthorize) return null;
|
|
8928
|
+
try {
|
|
8929
|
+
const res = await onAuthorize(req);
|
|
8930
|
+
if (res === false) {
|
|
8931
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
8932
|
+
}
|
|
8933
|
+
if (res instanceof Response) {
|
|
8934
|
+
return res;
|
|
8935
|
+
}
|
|
8936
|
+
return null;
|
|
8937
|
+
} catch (err) {
|
|
8938
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
8939
|
+
return NextResponse.json({ error: msg }, { status: 401 });
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
var RateLimiter = class {
|
|
8943
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
8944
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
8945
|
+
this.windowMs = windowMs;
|
|
8946
|
+
this.max = max;
|
|
8947
|
+
}
|
|
8948
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
8949
|
+
allow(key) {
|
|
8950
|
+
const now = Date.now();
|
|
8951
|
+
const cutoff = now - this.windowMs;
|
|
8952
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8953
|
+
existing.push(now);
|
|
8954
|
+
this.hits.set(key, existing);
|
|
8955
|
+
if (this.hits.size > 5e3) {
|
|
8956
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
8957
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
8958
|
+
}
|
|
8959
|
+
}
|
|
8960
|
+
return existing.length <= this.max;
|
|
8961
|
+
}
|
|
8962
|
+
retryAfterSec(key) {
|
|
8963
|
+
const now = Date.now();
|
|
8964
|
+
const cutoff = now - this.windowMs;
|
|
8965
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8966
|
+
if (existing.length === 0) return 0;
|
|
8967
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
8968
|
+
}
|
|
8969
|
+
};
|
|
8970
|
+
var _g = global;
|
|
8971
|
+
var _a;
|
|
8972
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
8973
|
+
function getRateLimitKey(req) {
|
|
8974
|
+
var _a2, _b;
|
|
8975
|
+
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";
|
|
8976
|
+
return `ip:${ip}`;
|
|
8977
|
+
}
|
|
8978
|
+
function checkRateLimit(req) {
|
|
8979
|
+
const key = getRateLimitKey(req);
|
|
8980
|
+
if (!rateLimiter.allow(key)) {
|
|
8981
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
8982
|
+
return new Response(
|
|
8983
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
8984
|
+
{
|
|
8985
|
+
status: 429,
|
|
8986
|
+
headers: {
|
|
8987
|
+
"Content-Type": "application/json",
|
|
8988
|
+
"Retry-After": String(retryAfter),
|
|
8989
|
+
"X-RateLimit-Limit": "30",
|
|
8990
|
+
"X-RateLimit-Window": "60"
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
);
|
|
8994
|
+
}
|
|
8995
|
+
return null;
|
|
8996
|
+
}
|
|
8997
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
8998
|
+
function sanitizeInput(raw) {
|
|
8999
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
9000
|
+
const trimmed = stripped.trim();
|
|
9001
|
+
if (!trimmed) {
|
|
9002
|
+
return { ok: false, error: "message must not be empty" };
|
|
9003
|
+
}
|
|
9004
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
9005
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
9006
|
+
}
|
|
9007
|
+
return { ok: true, value: trimmed };
|
|
9008
|
+
}
|
|
9009
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
9010
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
9011
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
9012
|
+
if (!_g[cacheKey]) {
|
|
9013
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
9014
|
+
}
|
|
9015
|
+
return _g[cacheKey];
|
|
9016
|
+
}
|
|
7341
9017
|
function sseFrame(payload) {
|
|
7342
9018
|
return `data: ${JSON.stringify(payload)}
|
|
7343
9019
|
|
|
@@ -7375,47 +9051,88 @@ var SSE_HEADERS = {
|
|
|
7375
9051
|
"X-Accel-Buffering": "no"
|
|
7376
9052
|
// Disable Nginx buffering for streaming
|
|
7377
9053
|
};
|
|
7378
|
-
function createChatHandler(configOrPlugin) {
|
|
7379
|
-
const plugin =
|
|
9054
|
+
function createChatHandler(configOrPlugin, options) {
|
|
9055
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9056
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9057
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7380
9058
|
return async function POST(req) {
|
|
9059
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9060
|
+
if (authResult) return authResult;
|
|
9061
|
+
const rateLimited = checkRateLimit(req);
|
|
9062
|
+
if (rateLimited) return rateLimited;
|
|
7381
9063
|
try {
|
|
7382
9064
|
const body = await req.json();
|
|
7383
|
-
const { message, history = [], namespace } = body;
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
9065
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9066
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9067
|
+
if (!sanitized.ok) {
|
|
9068
|
+
return NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
9069
|
+
}
|
|
9070
|
+
const message = sanitized.value;
|
|
9071
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9072
|
+
await storage.saveMessage(sessionId, {
|
|
9073
|
+
id: userMsgId,
|
|
9074
|
+
role: "user",
|
|
9075
|
+
content: message
|
|
9076
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7387
9077
|
const result = await plugin.chat(message, history, namespace);
|
|
7388
|
-
|
|
9078
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9079
|
+
await storage.saveMessage(sessionId, {
|
|
9080
|
+
id: assistantMsgId,
|
|
9081
|
+
role: "assistant",
|
|
9082
|
+
content: result.reply,
|
|
9083
|
+
sources: result.sources,
|
|
9084
|
+
uiTransformation: result.ui_transformation,
|
|
9085
|
+
trace: result.trace
|
|
9086
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9087
|
+
return NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9088
|
+
messageId: assistantMsgId,
|
|
9089
|
+
userMessageId: userMsgId
|
|
9090
|
+
}));
|
|
7389
9091
|
} catch (err) {
|
|
7390
9092
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7391
9093
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
7392
9094
|
}
|
|
7393
9095
|
};
|
|
7394
9096
|
}
|
|
7395
|
-
function createStreamHandler(configOrPlugin) {
|
|
7396
|
-
const plugin =
|
|
9097
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9098
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9099
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9100
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7397
9101
|
return async function POST(req) {
|
|
9102
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9103
|
+
if (authResult) return authResult;
|
|
9104
|
+
const rateLimited = checkRateLimit(req);
|
|
9105
|
+
if (rateLimited) return rateLimited;
|
|
7398
9106
|
let body;
|
|
7399
9107
|
try {
|
|
7400
9108
|
body = await req.json();
|
|
7401
9109
|
} catch (e) {
|
|
7402
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9110
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7403
9111
|
status: 400,
|
|
7404
9112
|
headers: { "Content-Type": "application/json" }
|
|
7405
9113
|
});
|
|
7406
9114
|
}
|
|
7407
|
-
const { message, history = [], namespace } = body;
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
9115
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9116
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9117
|
+
if (!sanitized.ok) {
|
|
9118
|
+
return new Response(
|
|
9119
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9120
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9121
|
+
);
|
|
7413
9122
|
}
|
|
9123
|
+
const message = sanitized.value;
|
|
9124
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9125
|
+
await storage.saveMessage(sessionId, {
|
|
9126
|
+
id: userMsgId,
|
|
9127
|
+
role: "user",
|
|
9128
|
+
content: message
|
|
9129
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9130
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7414
9131
|
const encoder = new TextEncoder();
|
|
7415
9132
|
let isActive = true;
|
|
7416
9133
|
const stream = new ReadableStream({
|
|
7417
9134
|
async start(controller) {
|
|
7418
|
-
var
|
|
9135
|
+
var _a2;
|
|
7419
9136
|
const enqueue = (text) => {
|
|
7420
9137
|
if (!isActive) return;
|
|
7421
9138
|
try {
|
|
@@ -7426,11 +9143,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7426
9143
|
};
|
|
7427
9144
|
try {
|
|
7428
9145
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9146
|
+
let fullReply = "";
|
|
7429
9147
|
try {
|
|
7430
9148
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7431
9149
|
const chunk = temp.value;
|
|
7432
9150
|
if (!isActive) break;
|
|
7433
9151
|
if (typeof chunk === "string") {
|
|
9152
|
+
fullReply += chunk;
|
|
7434
9153
|
enqueue(sseTextFrame(chunk));
|
|
7435
9154
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7436
9155
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7443,9 +9162,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7443
9162
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7444
9163
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7445
9164
|
}
|
|
9165
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7446
9166
|
if (sources.length > 0) {
|
|
7447
9167
|
try {
|
|
7448
|
-
|
|
9168
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7449
9169
|
if (uiTransformation) {
|
|
7450
9170
|
enqueue(sseUIFrame(uiTransformation));
|
|
7451
9171
|
}
|
|
@@ -7453,11 +9173,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7453
9173
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7454
9174
|
try {
|
|
7455
9175
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7456
|
-
if (fallback)
|
|
9176
|
+
if (fallback) {
|
|
9177
|
+
uiTransformation = fallback;
|
|
9178
|
+
enqueue(sseUIFrame(fallback));
|
|
9179
|
+
}
|
|
7457
9180
|
} catch (e) {
|
|
7458
9181
|
}
|
|
7459
9182
|
}
|
|
7460
9183
|
}
|
|
9184
|
+
await storage.saveMessage(sessionId, {
|
|
9185
|
+
id: assistantMsgId,
|
|
9186
|
+
role: "assistant",
|
|
9187
|
+
content: fullReply,
|
|
9188
|
+
sources,
|
|
9189
|
+
uiTransformation,
|
|
9190
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9191
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7461
9192
|
}
|
|
7462
9193
|
}
|
|
7463
9194
|
} catch (temp) {
|
|
@@ -7494,12 +9225,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7494
9225
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7495
9226
|
}
|
|
7496
9227
|
});
|
|
7497
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9228
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7498
9229
|
};
|
|
7499
9230
|
}
|
|
7500
|
-
function createIngestHandler(configOrPlugin) {
|
|
7501
|
-
const plugin =
|
|
9231
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9232
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9233
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7502
9234
|
return async function POST(req) {
|
|
9235
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9236
|
+
if (authResult) return authResult;
|
|
7503
9237
|
try {
|
|
7504
9238
|
const body = await req.json();
|
|
7505
9239
|
const { documents, namespace } = body;
|
|
@@ -7514,9 +9248,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7514
9248
|
}
|
|
7515
9249
|
};
|
|
7516
9250
|
}
|
|
7517
|
-
function createHealthHandler(configOrPlugin) {
|
|
7518
|
-
const plugin =
|
|
7519
|
-
|
|
9251
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9252
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9253
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9254
|
+
return async function GET(req) {
|
|
9255
|
+
if (req) {
|
|
9256
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9257
|
+
if (authResult) return authResult;
|
|
9258
|
+
}
|
|
7520
9259
|
try {
|
|
7521
9260
|
const health = await plugin.checkHealth();
|
|
7522
9261
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7531,9 +9270,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7531
9270
|
}
|
|
7532
9271
|
};
|
|
7533
9272
|
}
|
|
7534
|
-
function createUploadHandler(configOrPlugin) {
|
|
7535
|
-
const plugin =
|
|
9273
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9274
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9275
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7536
9276
|
return async function POST(req) {
|
|
9277
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9278
|
+
if (authResult) return authResult;
|
|
7537
9279
|
try {
|
|
7538
9280
|
const formData = await req.formData();
|
|
7539
9281
|
const files = formData.getAll("files");
|
|
@@ -7607,9 +9349,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7607
9349
|
}
|
|
7608
9350
|
};
|
|
7609
9351
|
}
|
|
7610
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
7611
|
-
const plugin =
|
|
9352
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9353
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9354
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7612
9355
|
return async function POST(req) {
|
|
9356
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9357
|
+
if (authResult) return authResult;
|
|
7613
9358
|
try {
|
|
7614
9359
|
const body = await req.json();
|
|
7615
9360
|
const { query, namespace } = body;
|
|
@@ -7624,13 +9369,108 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
7624
9369
|
}
|
|
7625
9370
|
};
|
|
7626
9371
|
}
|
|
7627
|
-
function
|
|
7628
|
-
const plugin =
|
|
7629
|
-
const
|
|
7630
|
-
const
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
9372
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9373
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9374
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9375
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9376
|
+
return async function handler(req) {
|
|
9377
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9378
|
+
if (authResult) return authResult;
|
|
9379
|
+
const url = new URL(req.url);
|
|
9380
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9381
|
+
if (req.method === "GET") {
|
|
9382
|
+
try {
|
|
9383
|
+
const history = await storage.getHistory(sessionId);
|
|
9384
|
+
return NextResponse.json({ history });
|
|
9385
|
+
} catch (err) {
|
|
9386
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9387
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9388
|
+
}
|
|
9389
|
+
} else if (req.method === "POST") {
|
|
9390
|
+
try {
|
|
9391
|
+
const body = await req.json().catch(() => ({}));
|
|
9392
|
+
const sid = body.sessionId || sessionId;
|
|
9393
|
+
await storage.clearHistory(sid);
|
|
9394
|
+
return NextResponse.json({ success: true });
|
|
9395
|
+
} catch (err) {
|
|
9396
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9397
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9398
|
+
}
|
|
9399
|
+
}
|
|
9400
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9401
|
+
};
|
|
9402
|
+
}
|
|
9403
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9404
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9405
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9406
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9407
|
+
return async function handler(req) {
|
|
9408
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9409
|
+
if (authResult) return authResult;
|
|
9410
|
+
if (req.method === "GET") {
|
|
9411
|
+
try {
|
|
9412
|
+
const url = new URL(req.url);
|
|
9413
|
+
const messageId = url.searchParams.get("messageId");
|
|
9414
|
+
if (!messageId) {
|
|
9415
|
+
const feedbackList = await storage.listFeedback();
|
|
9416
|
+
return NextResponse.json({ feedback: feedbackList });
|
|
9417
|
+
}
|
|
9418
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9419
|
+
return NextResponse.json({ feedback });
|
|
9420
|
+
} catch (err) {
|
|
9421
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9422
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9423
|
+
}
|
|
9424
|
+
} else if (req.method === "POST") {
|
|
9425
|
+
try {
|
|
9426
|
+
const body = await req.json();
|
|
9427
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9428
|
+
if (!messageId) {
|
|
9429
|
+
return NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9430
|
+
}
|
|
9431
|
+
if (!rating) {
|
|
9432
|
+
return NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9433
|
+
}
|
|
9434
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9435
|
+
return NextResponse.json({ success: true });
|
|
9436
|
+
} catch (err) {
|
|
9437
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9438
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9439
|
+
}
|
|
9440
|
+
}
|
|
9441
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9442
|
+
};
|
|
9443
|
+
}
|
|
9444
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9445
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9446
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9447
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9448
|
+
return async function GET(req) {
|
|
9449
|
+
if (req) {
|
|
9450
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9451
|
+
if (authResult) return authResult;
|
|
9452
|
+
}
|
|
9453
|
+
void req;
|
|
9454
|
+
try {
|
|
9455
|
+
const sessions = await storage.listSessions();
|
|
9456
|
+
return NextResponse.json({ sessions });
|
|
9457
|
+
} catch (err) {
|
|
9458
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9459
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9460
|
+
}
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
9463
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9464
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9465
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9466
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9467
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9468
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9469
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9470
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9471
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9472
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9473
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
7634
9474
|
async function routePostRequest(req, segment) {
|
|
7635
9475
|
switch (segment) {
|
|
7636
9476
|
case "chat":
|
|
@@ -7642,22 +9482,35 @@ function createRagHandler(configOrPlugin) {
|
|
|
7642
9482
|
case "suggestions":
|
|
7643
9483
|
return suggestionsHandler(req);
|
|
7644
9484
|
case "health":
|
|
7645
|
-
return healthHandler();
|
|
9485
|
+
return healthHandler(req);
|
|
9486
|
+
case "history":
|
|
9487
|
+
case "history/clear":
|
|
9488
|
+
return historyHandler(req);
|
|
9489
|
+
case "feedback":
|
|
9490
|
+
return feedbackHandler(req);
|
|
7646
9491
|
default:
|
|
7647
9492
|
return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
7648
9493
|
}
|
|
7649
9494
|
}
|
|
7650
9495
|
async function routeGetRequest(req, segment) {
|
|
7651
|
-
|
|
7652
|
-
|
|
9496
|
+
switch (segment) {
|
|
9497
|
+
case "health":
|
|
9498
|
+
return healthHandler(req);
|
|
9499
|
+
case "history":
|
|
9500
|
+
return historyHandler(req);
|
|
9501
|
+
case "feedback":
|
|
9502
|
+
return feedbackHandler(req);
|
|
9503
|
+
case "sessions":
|
|
9504
|
+
return sessionsHandler(req);
|
|
9505
|
+
default:
|
|
9506
|
+
return NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
7653
9507
|
}
|
|
7654
|
-
return NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
|
|
7655
9508
|
}
|
|
7656
9509
|
async function getSegment(context) {
|
|
7657
|
-
var
|
|
7658
|
-
const resolvedParams = typeof ((
|
|
9510
|
+
var _a2;
|
|
9511
|
+
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;
|
|
7659
9512
|
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
7660
|
-
return segments
|
|
9513
|
+
return segments.join("/") || "chat";
|
|
7661
9514
|
}
|
|
7662
9515
|
return {
|
|
7663
9516
|
GET: async (req, context) => {
|
|
@@ -7682,9 +9535,12 @@ function createRagHandler(configOrPlugin) {
|
|
|
7682
9535
|
}
|
|
7683
9536
|
export {
|
|
7684
9537
|
createChatHandler,
|
|
9538
|
+
createFeedbackHandler,
|
|
7685
9539
|
createHealthHandler,
|
|
9540
|
+
createHistoryHandler,
|
|
7686
9541
|
createIngestHandler,
|
|
7687
9542
|
createRagHandler,
|
|
9543
|
+
createSessionsHandler,
|
|
7688
9544
|
createStreamHandler,
|
|
7689
9545
|
createSuggestionsHandler,
|
|
7690
9546
|
createUploadHandler,
|