@retrivora-ai/rag-engine 1.9.6 → 1.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -113
- package/dist/{ILLMProvider-DNhyOYoK.d.mts → ILLMProvider-B8ROITYK.d.mts} +59 -8
- package/dist/{ILLMProvider-DNhyOYoK.d.ts → ILLMProvider-B8ROITYK.d.ts} +59 -8
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +2376 -489
- package/dist/handlers/index.mjs +2372 -489
- package/dist/{index-CjQdL0cX.d.ts → index-B8PbEFSY.d.mts} +17 -3
- package/dist/{index-CHL1jdYm.d.mts → index-BCPKUAVL.d.ts} +33 -41
- package/dist/{index-Hgbwl9X4.d.ts → index-CrxCy36A.d.mts} +33 -41
- package/dist/{index-C9v7-tWd.d.mts → index-DNvoi-sV.d.ts} +17 -3
- package/dist/index.css +695 -203
- package/dist/index.d.mts +37 -7
- package/dist/index.d.ts +37 -7
- package/dist/index.js +1197 -286
- package/dist/index.mjs +1221 -297
- package/dist/server.d.mts +62 -6
- package/dist/server.d.ts +62 -6
- package/dist/server.js +2526 -574
- package/dist/server.mjs +2517 -573
- package/package.json +12 -10
- package/src/app/constants.tsx +207 -212
- package/src/app/layout.tsx +4 -28
- package/src/app/types.ts +17 -17
- package/src/components/AmbientBackground.tsx +10 -10
- package/src/components/ArchitectureCard.tsx +43 -7
- package/src/components/ArchitectureCardsSection.tsx +37 -4
- package/src/components/ChatWidget.tsx +4 -1
- package/src/components/ChatWindow.tsx +9 -2
- package/src/components/CodeViewer.tsx +19 -14
- package/src/components/DocViewer.tsx +75 -15
- package/src/components/Documentation.tsx +111 -28
- package/src/components/Hero.tsx +103 -20
- package/src/components/Lifecycle.tsx +65 -25
- package/src/components/MarkdownComponents.tsx +44 -1
- package/src/components/MessageBubble.tsx +162 -50
- package/src/components/constants.tsx +279 -0
- package/src/config/RagConfig.ts +56 -10
- package/src/config/constants.ts +5 -0
- package/src/config/serverConfig.ts +15 -0
- package/src/core/ConfigResolver.ts +30 -25
- package/src/core/DatabaseStorage.ts +469 -0
- package/src/core/LicenseVerifier.ts +154 -0
- package/src/core/MultiAgentCoordinator.ts +239 -0
- package/src/core/Pipeline.ts +148 -16
- package/src/core/ProviderRegistry.ts +5 -5
- package/src/core/Retrivora.ts +52 -6
- package/src/core/VectorPlugin.ts +74 -11
- package/src/core/mcp.ts +261 -0
- package/src/exceptions/index.ts +52 -0
- package/src/handlers/index.ts +504 -47
- package/src/hooks/useRagChat.ts +100 -43
- package/src/hooks/useStoredMessages.ts +15 -4
- package/src/index.ts +7 -0
- package/src/llm/LLMFactory.ts +15 -6
- package/src/llm/providers/GroqProvider.ts +176 -0
- package/src/llm/providers/QwenProvider.ts +191 -0
- package/src/server.ts +23 -13
- package/src/types/chat.ts +16 -0
- package/src/types/props.ts +50 -1
- package/.env.example +0 -80
- package/LICENSE.txt +0 -21
package/dist/handlers/index.js
CHANGED
|
@@ -10,9 +10,6 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
10
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
11
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
12
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
13
|
-
var __typeError = (msg) => {
|
|
14
|
-
throw TypeError(msg);
|
|
15
|
-
};
|
|
16
13
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
17
14
|
var __spreadValues = (a, b) => {
|
|
18
15
|
for (var prop in b || (b = {}))
|
|
@@ -77,43 +74,15 @@ var __asyncGenerator = (__this, __arguments, generator) => {
|
|
|
77
74
|
}, method = (k, call, wait, clear) => it[k] = (x) => (call = new Promise((yes, no, run) => (run = () => resume(k, x, yes, no), q ? q.then(run) : run())), clear = () => q === wait && (q = 0), q = wait = call.then(clear, clear), call), q, it = {};
|
|
78
75
|
return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
|
|
79
76
|
};
|
|
80
|
-
var __yieldStar = (value) => {
|
|
81
|
-
var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
|
|
82
|
-
if (obj == null) {
|
|
83
|
-
obj = value[__knownSymbol("iterator")]();
|
|
84
|
-
method = (k) => it[k] = (x) => obj[k](x);
|
|
85
|
-
} else {
|
|
86
|
-
obj = obj.call(value);
|
|
87
|
-
method = (k) => it[k] = (v) => {
|
|
88
|
-
if (isAwait) {
|
|
89
|
-
isAwait = false;
|
|
90
|
-
if (k === "throw") throw v;
|
|
91
|
-
return v;
|
|
92
|
-
}
|
|
93
|
-
isAwait = true;
|
|
94
|
-
return {
|
|
95
|
-
done: false,
|
|
96
|
-
value: new __await(new Promise((resolve) => {
|
|
97
|
-
var x = obj[k](v);
|
|
98
|
-
if (!(x instanceof Object)) __typeError("Object expected");
|
|
99
|
-
resolve(x);
|
|
100
|
-
}), 1)
|
|
101
|
-
};
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
|
|
105
|
-
throw x;
|
|
106
|
-
}, "return" in obj && method("return"), it;
|
|
107
|
-
};
|
|
108
77
|
var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
|
|
109
78
|
|
|
110
79
|
// src/utils/templateUtils.ts
|
|
111
80
|
function isRecord(value) {
|
|
112
81
|
return typeof value === "object" && value !== null;
|
|
113
82
|
}
|
|
114
|
-
function resolvePath(obj,
|
|
115
|
-
if (!
|
|
116
|
-
return
|
|
83
|
+
function resolvePath(obj, path2) {
|
|
84
|
+
if (!path2 || !obj) return void 0;
|
|
85
|
+
return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
|
|
117
86
|
if (!isRecord(current) && !Array.isArray(current)) {
|
|
118
87
|
return void 0;
|
|
119
88
|
}
|
|
@@ -223,7 +192,7 @@ var init_PineconeProvider = __esm({
|
|
|
223
192
|
static getHealthChecker() {
|
|
224
193
|
return {
|
|
225
194
|
async check(config) {
|
|
226
|
-
var
|
|
195
|
+
var _a2, _b;
|
|
227
196
|
const opts = config.options || {};
|
|
228
197
|
const indexName = config.indexName;
|
|
229
198
|
const timestamp = Date.now();
|
|
@@ -231,7 +200,7 @@ var init_PineconeProvider = __esm({
|
|
|
231
200
|
const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
|
|
232
201
|
const client = new Pinecone2({ apiKey: opts.apiKey });
|
|
233
202
|
const indexes = await client.listIndexes();
|
|
234
|
-
const indexNames = (_b = (
|
|
203
|
+
const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
235
204
|
if (!indexNames.includes(indexName)) {
|
|
236
205
|
return {
|
|
237
206
|
healthy: false,
|
|
@@ -258,10 +227,10 @@ var init_PineconeProvider = __esm({
|
|
|
258
227
|
};
|
|
259
228
|
}
|
|
260
229
|
async initialize() {
|
|
261
|
-
var
|
|
230
|
+
var _a2, _b;
|
|
262
231
|
this.client = new import_pinecone.Pinecone({ apiKey: this.apiKey });
|
|
263
232
|
const indexes = await this.client.listIndexes();
|
|
264
|
-
const names = (_b = (
|
|
233
|
+
const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
265
234
|
if (!names.includes(this.indexName)) {
|
|
266
235
|
throw new Error(
|
|
267
236
|
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
@@ -273,12 +242,12 @@ var init_PineconeProvider = __esm({
|
|
|
273
242
|
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
274
243
|
}
|
|
275
244
|
async upsert(doc, namespace) {
|
|
276
|
-
var
|
|
245
|
+
var _a2;
|
|
277
246
|
await this.index(namespace).upsert({
|
|
278
247
|
records: [{
|
|
279
248
|
id: String(doc.id),
|
|
280
249
|
values: doc.vector,
|
|
281
|
-
metadata: __spreadValues({ content: doc.content }, (
|
|
250
|
+
metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
|
|
282
251
|
}]
|
|
283
252
|
});
|
|
284
253
|
}
|
|
@@ -286,29 +255,29 @@ var init_PineconeProvider = __esm({
|
|
|
286
255
|
const BATCH = 100;
|
|
287
256
|
for (let i = 0; i < docs.length; i += BATCH) {
|
|
288
257
|
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
289
|
-
var
|
|
258
|
+
var _a2;
|
|
290
259
|
return {
|
|
291
260
|
id: String(d.id),
|
|
292
261
|
values: d.vector,
|
|
293
|
-
metadata: __spreadValues({ content: d.content }, (
|
|
262
|
+
metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
|
|
294
263
|
};
|
|
295
264
|
});
|
|
296
265
|
await this.index(namespace).upsert({ records });
|
|
297
266
|
}
|
|
298
267
|
}
|
|
299
268
|
async query(vector, topK, namespace, filter) {
|
|
300
|
-
var
|
|
269
|
+
var _a2;
|
|
301
270
|
const pineconeFilter = this.sanitizeFilter(filter);
|
|
302
271
|
const result = await this.index(namespace).query(__spreadValues({
|
|
303
272
|
vector,
|
|
304
273
|
topK,
|
|
305
274
|
includeMetadata: true
|
|
306
275
|
}, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
|
|
307
|
-
return ((
|
|
308
|
-
var
|
|
276
|
+
return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
|
|
277
|
+
var _a3, _b;
|
|
309
278
|
return {
|
|
310
279
|
id: m.id,
|
|
311
|
-
score: (
|
|
280
|
+
score: (_a3 = m.score) != null ? _a3 : 0,
|
|
312
281
|
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
313
282
|
metadata: m.metadata
|
|
314
283
|
};
|
|
@@ -347,13 +316,13 @@ var init_PostgreSQLProvider = __esm({
|
|
|
347
316
|
init_BaseVectorProvider();
|
|
348
317
|
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
349
318
|
constructor(config) {
|
|
350
|
-
var
|
|
319
|
+
var _a2;
|
|
351
320
|
super(config);
|
|
352
321
|
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
353
322
|
const opts = config.options;
|
|
354
323
|
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
355
324
|
this.connectionString = opts.connectionString;
|
|
356
|
-
this.dimensions = (
|
|
325
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
|
|
357
326
|
}
|
|
358
327
|
static getValidator() {
|
|
359
328
|
return {
|
|
@@ -434,7 +403,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
434
403
|
}
|
|
435
404
|
}
|
|
436
405
|
async upsert(doc, namespace = "") {
|
|
437
|
-
var
|
|
406
|
+
var _a2;
|
|
438
407
|
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
439
408
|
await this.pool.query(
|
|
440
409
|
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
@@ -444,7 +413,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
444
413
|
content = EXCLUDED.content,
|
|
445
414
|
metadata = EXCLUDED.metadata,
|
|
446
415
|
embedding = EXCLUDED.embedding`,
|
|
447
|
-
[doc.id, namespace, doc.content, JSON.stringify((
|
|
416
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
|
|
448
417
|
);
|
|
449
418
|
}
|
|
450
419
|
async batchUpsert(docs, namespace = "") {
|
|
@@ -457,9 +426,9 @@ var init_PostgreSQLProvider = __esm({
|
|
|
457
426
|
const batch = docs.slice(i, i + BATCH_SIZE);
|
|
458
427
|
const values = [];
|
|
459
428
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
460
|
-
var
|
|
429
|
+
var _a2;
|
|
461
430
|
const offset = idx * 5;
|
|
462
|
-
values.push(doc.id, namespace, doc.content, JSON.stringify((
|
|
431
|
+
values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
|
|
463
432
|
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
|
|
464
433
|
}).join(", ");
|
|
465
434
|
const query = `
|
|
@@ -542,8 +511,8 @@ var init_PostgreSQLProvider = __esm({
|
|
|
542
511
|
|
|
543
512
|
// src/utils/synonyms.ts
|
|
544
513
|
function resolveMetadataValue(meta, uiKey) {
|
|
545
|
-
var
|
|
546
|
-
const synonyms = (
|
|
514
|
+
var _a2;
|
|
515
|
+
const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
|
|
547
516
|
const keys = Object.keys(meta);
|
|
548
517
|
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
549
518
|
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
@@ -630,14 +599,14 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
630
599
|
init_synonyms();
|
|
631
600
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
632
601
|
constructor(config) {
|
|
633
|
-
var
|
|
602
|
+
var _a2, _b, _c;
|
|
634
603
|
super(config);
|
|
635
604
|
const opts = config.options || {};
|
|
636
605
|
if (!opts.connectionString) {
|
|
637
606
|
throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
|
|
638
607
|
}
|
|
639
608
|
this.connectionString = opts.connectionString;
|
|
640
|
-
this.dimensions = (
|
|
609
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
|
|
641
610
|
this.tables = [];
|
|
642
611
|
const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
|
|
643
612
|
this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
|
|
@@ -695,11 +664,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
695
664
|
* Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
|
|
696
665
|
*/
|
|
697
666
|
async batchUpsert(docs, namespace = "") {
|
|
698
|
-
var
|
|
667
|
+
var _a2;
|
|
699
668
|
if (docs.length === 0) return;
|
|
700
669
|
const docsByFile = {};
|
|
701
670
|
for (const doc of docs) {
|
|
702
|
-
const fileName = ((
|
|
671
|
+
const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
|
|
703
672
|
if (!docsByFile[fileName]) docsByFile[fileName] = [];
|
|
704
673
|
docsByFile[fileName].push(doc);
|
|
705
674
|
}
|
|
@@ -752,11 +721,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
752
721
|
const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
|
|
753
722
|
const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
|
|
754
723
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
755
|
-
var
|
|
724
|
+
var _a3, _b;
|
|
756
725
|
const offset = idx * (5 + csvHeaders.length);
|
|
757
726
|
values.push(doc.id);
|
|
758
727
|
for (const h of csvHeaders) {
|
|
759
|
-
values.push(String(((
|
|
728
|
+
values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
|
|
760
729
|
}
|
|
761
730
|
values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
|
|
762
731
|
const docPlaceholders = [];
|
|
@@ -795,7 +764,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
795
764
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
796
765
|
*/
|
|
797
766
|
async query(vector, topK, _namespace, _filter) {
|
|
798
|
-
var
|
|
767
|
+
var _a2;
|
|
799
768
|
if (!this.pool) {
|
|
800
769
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
801
770
|
}
|
|
@@ -826,11 +795,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
826
795
|
const filterParams = [];
|
|
827
796
|
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
828
797
|
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
829
|
-
var
|
|
798
|
+
var _a4;
|
|
830
799
|
filterParams.push(String(val));
|
|
831
800
|
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
832
801
|
const paramIdx = baseOffset + filterParams.length;
|
|
833
|
-
const synonyms = (
|
|
802
|
+
const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
|
|
834
803
|
const keysToCheck = [key, ...synonyms];
|
|
835
804
|
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
836
805
|
`metadata->>'${k}'`,
|
|
@@ -899,7 +868,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
899
868
|
}
|
|
900
869
|
const tableResults = [];
|
|
901
870
|
for (const row of result.rows) {
|
|
902
|
-
const
|
|
871
|
+
const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
|
|
903
872
|
delete rest.embedding;
|
|
904
873
|
delete rest.vector_score;
|
|
905
874
|
delete rest.keyword_score;
|
|
@@ -928,10 +897,10 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
928
897
|
}
|
|
929
898
|
allResults.sort((a, b) => b.score - a.score);
|
|
930
899
|
if (allResults.length === 0) return [];
|
|
931
|
-
const bestMatchTable = (
|
|
900
|
+
const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
|
|
932
901
|
const finalSorted = allResults.filter((res) => {
|
|
933
|
-
var
|
|
934
|
-
return ((
|
|
902
|
+
var _a3;
|
|
903
|
+
return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
|
|
935
904
|
});
|
|
936
905
|
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
937
906
|
console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
@@ -1336,14 +1305,14 @@ var init_QdrantProvider = __esm({
|
|
|
1336
1305
|
* Samples points from the collection to discover available payload fields.
|
|
1337
1306
|
*/
|
|
1338
1307
|
async discoverSchema() {
|
|
1339
|
-
var
|
|
1308
|
+
var _a2;
|
|
1340
1309
|
try {
|
|
1341
1310
|
const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
|
|
1342
1311
|
limit: 20,
|
|
1343
1312
|
with_payload: true,
|
|
1344
1313
|
with_vector: false
|
|
1345
1314
|
});
|
|
1346
|
-
const points = ((
|
|
1315
|
+
const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
|
|
1347
1316
|
const keys = /* @__PURE__ */ new Set();
|
|
1348
1317
|
for (const point of points) {
|
|
1349
1318
|
const payload = point.payload || {};
|
|
@@ -1369,12 +1338,12 @@ var init_QdrantProvider = __esm({
|
|
|
1369
1338
|
* Ensures the collection exists. Creates it if missing.
|
|
1370
1339
|
*/
|
|
1371
1340
|
async ensureCollection() {
|
|
1372
|
-
var
|
|
1341
|
+
var _a2;
|
|
1373
1342
|
try {
|
|
1374
1343
|
await this.http.get(`/collections/${this.indexName}`);
|
|
1375
1344
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
1376
1345
|
} catch (err) {
|
|
1377
|
-
if (import_axios4.default.isAxiosError(err) && ((
|
|
1346
|
+
if (import_axios4.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1378
1347
|
const opts = this.config.options;
|
|
1379
1348
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1380
1349
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
@@ -1394,7 +1363,7 @@ var init_QdrantProvider = __esm({
|
|
|
1394
1363
|
* Ensures that a payload field has an index.
|
|
1395
1364
|
*/
|
|
1396
1365
|
async ensureIndex(fieldName, schema = "keyword") {
|
|
1397
|
-
var
|
|
1366
|
+
var _a2;
|
|
1398
1367
|
let fullPath = fieldName;
|
|
1399
1368
|
if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
|
|
1400
1369
|
fullPath = `${this.metadataField}.${fieldName}`;
|
|
@@ -1407,7 +1376,7 @@ var init_QdrantProvider = __esm({
|
|
|
1407
1376
|
console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
|
|
1408
1377
|
} catch (err) {
|
|
1409
1378
|
let status;
|
|
1410
|
-
if (import_axios4.default.isAxiosError(err)) status = (
|
|
1379
|
+
if (import_axios4.default.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
|
|
1411
1380
|
if (status === 409) return;
|
|
1412
1381
|
console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
|
|
1413
1382
|
}
|
|
@@ -1436,7 +1405,7 @@ var init_QdrantProvider = __esm({
|
|
|
1436
1405
|
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
1437
1406
|
}
|
|
1438
1407
|
async query(vector, topK, namespace, _filter) {
|
|
1439
|
-
var
|
|
1408
|
+
var _a2;
|
|
1440
1409
|
const must = [];
|
|
1441
1410
|
if (namespace) {
|
|
1442
1411
|
must.push({ key: "namespace", match: { value: namespace } });
|
|
@@ -1458,7 +1427,7 @@ var init_QdrantProvider = __esm({
|
|
|
1458
1427
|
limit: topK,
|
|
1459
1428
|
with_payload: true,
|
|
1460
1429
|
params: {
|
|
1461
|
-
hnsw_ef: ((
|
|
1430
|
+
hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
|
|
1462
1431
|
exact: false
|
|
1463
1432
|
},
|
|
1464
1433
|
filter: must.length > 0 ? { must } : void 0
|
|
@@ -1553,13 +1522,13 @@ var init_ChromaDBProvider = __esm({
|
|
|
1553
1522
|
* Get or create the ChromaDB collection.
|
|
1554
1523
|
*/
|
|
1555
1524
|
async initialize() {
|
|
1556
|
-
var
|
|
1525
|
+
var _a2;
|
|
1557
1526
|
try {
|
|
1558
1527
|
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1559
1528
|
this.collectionId = data.id;
|
|
1560
1529
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1561
1530
|
} catch (err) {
|
|
1562
|
-
if (import_axios5.default.isAxiosError(err) && ((
|
|
1531
|
+
if (import_axios5.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1563
1532
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1564
1533
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1565
1534
|
name: this.indexName
|
|
@@ -1780,7 +1749,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1780
1749
|
await this.http.post("/v1/batch/objects", payload);
|
|
1781
1750
|
}
|
|
1782
1751
|
async query(vector, topK, namespace, _filter) {
|
|
1783
|
-
var
|
|
1752
|
+
var _a2, _b;
|
|
1784
1753
|
const queryText = _filter == null ? void 0 : _filter.queryText;
|
|
1785
1754
|
const sanitizedFilter = this.sanitizeFilter(_filter);
|
|
1786
1755
|
const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
|
|
@@ -1806,7 +1775,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1806
1775
|
`
|
|
1807
1776
|
};
|
|
1808
1777
|
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1809
|
-
const results = ((_b = (
|
|
1778
|
+
const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1810
1779
|
return results.map((res) => ({
|
|
1811
1780
|
id: res["_additional"].id,
|
|
1812
1781
|
score: 1 - res["_additional"].distance,
|
|
@@ -1859,10 +1828,10 @@ var init_WeaviateProvider = __esm({
|
|
|
1859
1828
|
return `{ operator: And, operands: [${operands.join(", ")}] }`;
|
|
1860
1829
|
}
|
|
1861
1830
|
weaviateOperand(key, value) {
|
|
1862
|
-
const
|
|
1863
|
-
if (typeof value === "number") return `{ ${
|
|
1864
|
-
if (typeof value === "boolean") return `{ ${
|
|
1865
|
-
return `{ ${
|
|
1831
|
+
const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
|
|
1832
|
+
if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
|
|
1833
|
+
if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
|
|
1834
|
+
return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
|
|
1866
1835
|
}
|
|
1867
1836
|
};
|
|
1868
1837
|
}
|
|
@@ -1889,21 +1858,21 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1889
1858
|
}
|
|
1890
1859
|
}
|
|
1891
1860
|
async initialize() {
|
|
1892
|
-
var
|
|
1861
|
+
var _a2;
|
|
1893
1862
|
this.http = import_axios8.default.create({
|
|
1894
1863
|
baseURL: this.opts.baseUrl,
|
|
1895
1864
|
headers: __spreadValues({
|
|
1896
1865
|
"Content-Type": "application/json"
|
|
1897
1866
|
}, this.opts.headers),
|
|
1898
|
-
timeout: (
|
|
1867
|
+
timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
|
|
1899
1868
|
});
|
|
1900
1869
|
if (!await this.ping()) {
|
|
1901
1870
|
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1902
1871
|
}
|
|
1903
1872
|
}
|
|
1904
1873
|
async upsert(doc, namespace) {
|
|
1905
|
-
var
|
|
1906
|
-
const endpoint = (
|
|
1874
|
+
var _a2, _b, _c;
|
|
1875
|
+
const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
|
|
1907
1876
|
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1908
1877
|
id: "{{id}}",
|
|
1909
1878
|
vector: "{{vector}}",
|
|
@@ -1936,8 +1905,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1936
1905
|
}
|
|
1937
1906
|
}
|
|
1938
1907
|
async query(vector, topK, namespace, filter) {
|
|
1939
|
-
var
|
|
1940
|
-
const endpoint = (
|
|
1908
|
+
var _a2, _b;
|
|
1909
|
+
const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
|
|
1941
1910
|
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1942
1911
|
vector: "{{vector}}",
|
|
1943
1912
|
limit: "{{topK}}",
|
|
@@ -1963,12 +1932,12 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1963
1932
|
);
|
|
1964
1933
|
}
|
|
1965
1934
|
return results.map((item) => {
|
|
1966
|
-
var
|
|
1935
|
+
var _a3, _b2, _c, _d, _e, _f, _g2;
|
|
1967
1936
|
return {
|
|
1968
|
-
id: item[(
|
|
1937
|
+
id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
|
|
1969
1938
|
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1970
1939
|
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1971
|
-
metadata: (
|
|
1940
|
+
metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
|
|
1972
1941
|
};
|
|
1973
1942
|
});
|
|
1974
1943
|
} catch (error) {
|
|
@@ -1978,8 +1947,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1978
1947
|
}
|
|
1979
1948
|
}
|
|
1980
1949
|
async delete(id, namespace) {
|
|
1981
|
-
var
|
|
1982
|
-
const endpoint = (
|
|
1950
|
+
var _a2, _b;
|
|
1951
|
+
const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
|
|
1983
1952
|
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1984
1953
|
id: "{{id}}",
|
|
1985
1954
|
namespace: "{{namespace}}"
|
|
@@ -1997,8 +1966,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1997
1966
|
}
|
|
1998
1967
|
}
|
|
1999
1968
|
async deleteNamespace(namespace) {
|
|
2000
|
-
var
|
|
2001
|
-
const endpoint = (
|
|
1969
|
+
var _a2;
|
|
1970
|
+
const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
|
|
2002
1971
|
try {
|
|
2003
1972
|
await this.http.post(endpoint, { namespace });
|
|
2004
1973
|
} catch (error) {
|
|
@@ -2008,9 +1977,9 @@ var init_UniversalVectorProvider = __esm({
|
|
|
2008
1977
|
}
|
|
2009
1978
|
}
|
|
2010
1979
|
async ping() {
|
|
2011
|
-
var
|
|
1980
|
+
var _a2;
|
|
2012
1981
|
try {
|
|
2013
|
-
const endpoint = (
|
|
1982
|
+
const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
|
|
2014
1983
|
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
2015
1984
|
return response.status >= 200 && response.status < 300;
|
|
2016
1985
|
} catch (e) {
|
|
@@ -2102,8 +2071,12 @@ var init_SimpleGraphProvider = __esm({
|
|
|
2102
2071
|
var handlers_exports = {};
|
|
2103
2072
|
__export(handlers_exports, {
|
|
2104
2073
|
createChatHandler: () => createChatHandler,
|
|
2074
|
+
createFeedbackHandler: () => createFeedbackHandler,
|
|
2105
2075
|
createHealthHandler: () => createHealthHandler,
|
|
2076
|
+
createHistoryHandler: () => createHistoryHandler,
|
|
2106
2077
|
createIngestHandler: () => createIngestHandler,
|
|
2078
|
+
createRagHandler: () => createRagHandler,
|
|
2079
|
+
createSessionsHandler: () => createSessionsHandler,
|
|
2107
2080
|
createStreamHandler: () => createStreamHandler,
|
|
2108
2081
|
createSuggestionsHandler: () => createSuggestionsHandler,
|
|
2109
2082
|
createUploadHandler: () => createUploadHandler,
|
|
@@ -2140,6 +2113,8 @@ var LLM_PROVIDERS = [
|
|
|
2140
2113
|
"anthropic",
|
|
2141
2114
|
"ollama",
|
|
2142
2115
|
"gemini",
|
|
2116
|
+
"groq",
|
|
2117
|
+
"qwen",
|
|
2143
2118
|
"rest",
|
|
2144
2119
|
"universal_rest",
|
|
2145
2120
|
"custom"
|
|
@@ -2148,6 +2123,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2148
2123
|
"openai",
|
|
2149
2124
|
"ollama",
|
|
2150
2125
|
"gemini",
|
|
2126
|
+
"qwen",
|
|
2151
2127
|
"rest",
|
|
2152
2128
|
"universal_rest",
|
|
2153
2129
|
"custom"
|
|
@@ -2156,6 +2132,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2156
2132
|
"openai",
|
|
2157
2133
|
"ollama",
|
|
2158
2134
|
"gemini",
|
|
2135
|
+
"qwen",
|
|
2159
2136
|
"rest",
|
|
2160
2137
|
"universal_rest"
|
|
2161
2138
|
];
|
|
@@ -2163,8 +2140,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2163
2140
|
|
|
2164
2141
|
// src/config/serverConfig.ts
|
|
2165
2142
|
function readString(env, name) {
|
|
2166
|
-
var
|
|
2167
|
-
const value = (
|
|
2143
|
+
var _a2;
|
|
2144
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2168
2145
|
return value ? value : void 0;
|
|
2169
2146
|
}
|
|
2170
2147
|
function readNumber(env, name, fallback) {
|
|
@@ -2177,23 +2154,23 @@ function readNumber(env, name, fallback) {
|
|
|
2177
2154
|
return parsed;
|
|
2178
2155
|
}
|
|
2179
2156
|
function readEnum(env, name, fallback, allowed) {
|
|
2180
|
-
var
|
|
2181
|
-
const value = (
|
|
2157
|
+
var _a2;
|
|
2158
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2182
2159
|
if (allowed.includes(value)) {
|
|
2183
2160
|
return value;
|
|
2184
2161
|
}
|
|
2185
2162
|
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
2186
2163
|
}
|
|
2187
2164
|
function getEnvConfig(env = process.env, base) {
|
|
2188
|
-
var
|
|
2189
|
-
const projectId = (_c = (_b = (
|
|
2165
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa;
|
|
2166
|
+
const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
|
|
2190
2167
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2191
2168
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2192
2169
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2193
2170
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2194
2171
|
const vectorDbOptions = {};
|
|
2195
2172
|
if (vectorProvider === "pinecone") {
|
|
2196
|
-
vectorDbOptions.apiKey = (
|
|
2173
|
+
vectorDbOptions.apiKey = (_g2 = (_f = readString(env, "PINECONE_API_KEY")) != null ? _f : (_e = (_d = base == null ? void 0 : base.vectorDb) == null ? void 0 : _d.options) == null ? void 0 : _e.apiKey) != null ? _g2 : "";
|
|
2197
2174
|
vectorDbOptions.indexName = (_l = (_i = readString(env, "PINECONE_INDEX")) != null ? _i : (_h = base == null ? void 0 : base.vectorDb) == null ? void 0 : _h.indexName) != null ? _l : (_k = (_j = base == null ? void 0 : base.vectorDb) == null ? void 0 : _j.options) == null ? void 0 : _k.indexName;
|
|
2198
2175
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2199
2176
|
vectorDbOptions.connectionString = (_q = (_p = (_m = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _m : readString(env, "POSTGRES_URL")) != null ? _p : (_o = (_n = base == null ? void 0 : base.vectorDb) == null ? void 0 : _n.options) == null ? void 0 : _o.connectionString) != null ? _q : "";
|
|
@@ -2255,17 +2232,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2255
2232
|
rest: "default",
|
|
2256
2233
|
custom: "default"
|
|
2257
2234
|
};
|
|
2258
|
-
return __spreadValues({
|
|
2235
|
+
return __spreadProps(__spreadValues({
|
|
2259
2236
|
projectId,
|
|
2237
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2260
2238
|
vectorDb: {
|
|
2261
2239
|
provider: vectorProvider,
|
|
2262
|
-
indexName: (
|
|
2240
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2263
2241
|
options: vectorDbOptions
|
|
2264
2242
|
},
|
|
2265
2243
|
llm: {
|
|
2266
2244
|
provider: llmProvider,
|
|
2267
|
-
model: (
|
|
2268
|
-
apiKey: (
|
|
2245
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2246
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2269
2247
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2270
2248
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2271
2249
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2278,7 +2256,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2278
2256
|
},
|
|
2279
2257
|
embedding: {
|
|
2280
2258
|
provider: embeddingProvider,
|
|
2281
|
-
model: (
|
|
2259
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2282
2260
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2283
2261
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2284
2262
|
dimensions: embeddingDimensions,
|
|
@@ -2289,30 +2267,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2289
2267
|
}
|
|
2290
2268
|
},
|
|
2291
2269
|
ui: {
|
|
2292
|
-
title: (
|
|
2293
|
-
subtitle: (
|
|
2294
|
-
primaryColor: (
|
|
2295
|
-
accentColor: (
|
|
2296
|
-
logoUrl: (
|
|
2297
|
-
placeholder: (
|
|
2298
|
-
showSources: ((
|
|
2299
|
-
welcomeMessage: (
|
|
2300
|
-
visualStyle: (
|
|
2301
|
-
borderRadius: (
|
|
2302
|
-
allowUpload: ((
|
|
2270
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2271
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2272
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2273
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2274
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2275
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2276
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2277
|
+
welcomeMessage: (_Ca = (_Ba = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _Ba : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Ca : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
2278
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2279
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2280
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2303
2281
|
},
|
|
2304
2282
|
rag: {
|
|
2305
2283
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2306
2284
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2307
2285
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2308
2286
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2309
|
-
filterableFields: (
|
|
2287
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2310
2288
|
// Query pipeline toggles — read from .env.local
|
|
2311
2289
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2312
2290
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2313
2291
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2314
|
-
architecture: (
|
|
2315
|
-
chunkingStrategy: (
|
|
2292
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2293
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2316
2294
|
uiMapping: (() => {
|
|
2317
2295
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2318
2296
|
if (!raw) return void 0;
|
|
@@ -2322,6 +2300,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2322
2300
|
return void 0;
|
|
2323
2301
|
}
|
|
2324
2302
|
})()
|
|
2303
|
+
},
|
|
2304
|
+
telemetry: {
|
|
2305
|
+
enabled: readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_Ma = base == null ? void 0 : base.telemetry) == null ? void 0 : _Ma.enabled) || false,
|
|
2306
|
+
url: (_Qa = (_Pa = (_Na = readString(env, "TELEMETRY_URL")) != null ? _Na : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _Pa : (_Oa = base == null ? void 0 : base.telemetry) == null ? void 0 : _Oa.url) != null ? _Qa : "/api/telemetry"
|
|
2325
2307
|
}
|
|
2326
2308
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2327
2309
|
graphDb: {
|
|
@@ -2332,29 +2314,21 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2332
2314
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2333
2315
|
}
|
|
2334
2316
|
}
|
|
2335
|
-
} : {})
|
|
2317
|
+
} : {}), {
|
|
2318
|
+
mcpServers: (() => {
|
|
2319
|
+
var _a3;
|
|
2320
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2321
|
+
if (!raw) return void 0;
|
|
2322
|
+
try {
|
|
2323
|
+
return JSON.parse(raw);
|
|
2324
|
+
} catch (e) {
|
|
2325
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2326
|
+
return void 0;
|
|
2327
|
+
}
|
|
2328
|
+
})()
|
|
2329
|
+
});
|
|
2336
2330
|
}
|
|
2337
2331
|
|
|
2338
|
-
// src/exceptions/index.ts
|
|
2339
|
-
var RetrivoraError = class extends Error {
|
|
2340
|
-
constructor(message, code, details) {
|
|
2341
|
-
super(message);
|
|
2342
|
-
this.name = new.target.name;
|
|
2343
|
-
this.code = code;
|
|
2344
|
-
this.details = details;
|
|
2345
|
-
}
|
|
2346
|
-
};
|
|
2347
|
-
var ProviderNotFoundException = class extends RetrivoraError {
|
|
2348
|
-
constructor(providerType, provider, details) {
|
|
2349
|
-
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
2350
|
-
}
|
|
2351
|
-
};
|
|
2352
|
-
var ConfigurationException = class extends RetrivoraError {
|
|
2353
|
-
constructor(message, details) {
|
|
2354
|
-
super(message, "CONFIGURATION_ERROR", details);
|
|
2355
|
-
}
|
|
2356
|
-
};
|
|
2357
|
-
|
|
2358
2332
|
// src/core/ConfigResolver.ts
|
|
2359
2333
|
var ConfigResolver = class {
|
|
2360
2334
|
/**
|
|
@@ -2378,7 +2352,8 @@ var ConfigResolver = class {
|
|
|
2378
2352
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2379
2353
|
}) : envConfig.embedding,
|
|
2380
2354
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2381
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2355
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2356
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2382
2357
|
});
|
|
2383
2358
|
}
|
|
2384
2359
|
/**
|
|
@@ -2387,10 +2362,10 @@ var ConfigResolver = class {
|
|
|
2387
2362
|
* fallback behavior.
|
|
2388
2363
|
*/
|
|
2389
2364
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2390
|
-
var
|
|
2365
|
+
var _a2;
|
|
2391
2366
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2392
2367
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2393
|
-
vectorDb: (
|
|
2368
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2394
2369
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2395
2370
|
});
|
|
2396
2371
|
return this.resolve(normalized, env);
|
|
@@ -2400,21 +2375,21 @@ var ConfigResolver = class {
|
|
|
2400
2375
|
*/
|
|
2401
2376
|
static validate(config) {
|
|
2402
2377
|
if (!config.projectId) {
|
|
2403
|
-
throw new
|
|
2378
|
+
throw new Error("[ConfigResolver] projectId is required");
|
|
2404
2379
|
}
|
|
2405
2380
|
if (!config.vectorDb.provider) {
|
|
2406
|
-
throw new
|
|
2381
|
+
throw new Error("[ConfigResolver] vectorDb.provider is required");
|
|
2407
2382
|
}
|
|
2408
2383
|
if (!config.llm.provider) {
|
|
2409
|
-
throw new
|
|
2384
|
+
throw new Error("[ConfigResolver] llm.provider is required");
|
|
2410
2385
|
}
|
|
2411
2386
|
}
|
|
2412
2387
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2413
|
-
var
|
|
2388
|
+
var _a2, _b, _c, _d, _e;
|
|
2414
2389
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2415
2390
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2416
2391
|
if (retrieval) {
|
|
2417
|
-
normalized.topK = (
|
|
2392
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2418
2393
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2419
2394
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2420
2395
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
@@ -2496,8 +2471,8 @@ var OpenAIProvider = class {
|
|
|
2496
2471
|
const apiKey = config.apiKey;
|
|
2497
2472
|
const modelName = config.model;
|
|
2498
2473
|
try {
|
|
2499
|
-
const
|
|
2500
|
-
const client = new
|
|
2474
|
+
const OpenAI4 = await import("openai");
|
|
2475
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2501
2476
|
const models = await client.models.list();
|
|
2502
2477
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2503
2478
|
return {
|
|
@@ -2518,8 +2493,8 @@ var OpenAIProvider = class {
|
|
|
2518
2493
|
};
|
|
2519
2494
|
}
|
|
2520
2495
|
async chat(messages, context, options) {
|
|
2521
|
-
var
|
|
2522
|
-
const basePrompt = (_b = (
|
|
2496
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2497
|
+
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.";
|
|
2523
2498
|
const systemMessage = {
|
|
2524
2499
|
role: "system",
|
|
2525
2500
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2538,12 +2513,12 @@ var OpenAIProvider = class {
|
|
|
2538
2513
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2539
2514
|
stop: options == null ? void 0 : options.stop
|
|
2540
2515
|
});
|
|
2541
|
-
return (_i = (_h = (
|
|
2516
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2542
2517
|
}
|
|
2543
2518
|
chatStream(messages, context, options) {
|
|
2544
2519
|
return __asyncGenerator(this, null, function* () {
|
|
2545
|
-
var
|
|
2546
|
-
const basePrompt = (_b = (
|
|
2520
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2521
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2547
2522
|
const systemMessage = {
|
|
2548
2523
|
role: "system",
|
|
2549
2524
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2569,7 +2544,7 @@ var OpenAIProvider = class {
|
|
|
2569
2544
|
try {
|
|
2570
2545
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2571
2546
|
const chunk = temp.value;
|
|
2572
|
-
const content = ((_h = (
|
|
2547
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2573
2548
|
if (content) yield content;
|
|
2574
2549
|
}
|
|
2575
2550
|
} catch (temp) {
|
|
@@ -2589,8 +2564,8 @@ var OpenAIProvider = class {
|
|
|
2589
2564
|
return results[0];
|
|
2590
2565
|
}
|
|
2591
2566
|
async batchEmbed(texts, options) {
|
|
2592
|
-
var
|
|
2593
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2567
|
+
var _a2, _b, _c, _d, _e;
|
|
2568
|
+
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";
|
|
2594
2569
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2595
2570
|
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
2596
2571
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2667,8 +2642,8 @@ var AnthropicProvider = class {
|
|
|
2667
2642
|
};
|
|
2668
2643
|
}
|
|
2669
2644
|
async chat(messages, context, options) {
|
|
2670
|
-
var
|
|
2671
|
-
const basePrompt = (_b = (
|
|
2645
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2646
|
+
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.";
|
|
2672
2647
|
const system = buildSystemContent(basePrompt, context);
|
|
2673
2648
|
const anthropicMessages = messages.map((m) => ({
|
|
2674
2649
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2679,7 +2654,7 @@ var AnthropicProvider = class {
|
|
|
2679
2654
|
const extraParams = {};
|
|
2680
2655
|
if (isThinkingEnabled && isClaude37) {
|
|
2681
2656
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2682
|
-
const maxTokens = (
|
|
2657
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2683
2658
|
const budget = Math.min(
|
|
2684
2659
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2685
2660
|
maxTokens - 1
|
|
@@ -2706,8 +2681,8 @@ var AnthropicProvider = class {
|
|
|
2706
2681
|
}
|
|
2707
2682
|
chatStream(messages, context, options) {
|
|
2708
2683
|
return __asyncGenerator(this, null, function* () {
|
|
2709
|
-
var
|
|
2710
|
-
const basePrompt = (_b = (
|
|
2684
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2685
|
+
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.";
|
|
2711
2686
|
const system = buildSystemContent(basePrompt, context);
|
|
2712
2687
|
const anthropicMessages = messages.map((m) => ({
|
|
2713
2688
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2718,7 +2693,7 @@ var AnthropicProvider = class {
|
|
|
2718
2693
|
const extraParams = {};
|
|
2719
2694
|
if (isThinkingEnabled && isClaude37) {
|
|
2720
2695
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2721
|
-
const maxTokens = (
|
|
2696
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2722
2697
|
const budget = Math.min(
|
|
2723
2698
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2724
2699
|
maxTokens - 1
|
|
@@ -2791,8 +2766,8 @@ var AnthropicProvider = class {
|
|
|
2791
2766
|
var import_axios = __toESM(require("axios"));
|
|
2792
2767
|
var OllamaProvider = class {
|
|
2793
2768
|
constructor(llmConfig, embeddingConfig) {
|
|
2794
|
-
var
|
|
2795
|
-
const baseURL = (
|
|
2769
|
+
var _a2, _b;
|
|
2770
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2796
2771
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2797
2772
|
this.http = import_axios.default.create({ baseURL, timeout });
|
|
2798
2773
|
this.llmConfig = llmConfig;
|
|
@@ -2850,8 +2825,8 @@ var OllamaProvider = class {
|
|
|
2850
2825
|
};
|
|
2851
2826
|
}
|
|
2852
2827
|
async chat(messages, context, options) {
|
|
2853
|
-
var
|
|
2854
|
-
const basePrompt = (_b = (
|
|
2828
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2829
|
+
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.";
|
|
2855
2830
|
const system = buildSystemContent(basePrompt, context);
|
|
2856
2831
|
const { data } = await this.http.post("/api/chat", {
|
|
2857
2832
|
model: this.llmConfig.model,
|
|
@@ -2869,8 +2844,8 @@ var OllamaProvider = class {
|
|
|
2869
2844
|
}
|
|
2870
2845
|
chatStream(messages, context, options) {
|
|
2871
2846
|
return __asyncGenerator(this, null, function* () {
|
|
2872
|
-
var
|
|
2873
|
-
const basePrompt = (_b = (
|
|
2847
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2848
|
+
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.";
|
|
2874
2849
|
const system = buildSystemContent(basePrompt, context);
|
|
2875
2850
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2876
2851
|
model: this.llmConfig.model,
|
|
@@ -2899,7 +2874,7 @@ var OllamaProvider = class {
|
|
|
2899
2874
|
if (!line.trim()) continue;
|
|
2900
2875
|
try {
|
|
2901
2876
|
const json = JSON.parse(line);
|
|
2902
|
-
if ((
|
|
2877
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2903
2878
|
yield json.message.content;
|
|
2904
2879
|
}
|
|
2905
2880
|
if (json.done) return;
|
|
@@ -2928,10 +2903,10 @@ var OllamaProvider = class {
|
|
|
2928
2903
|
});
|
|
2929
2904
|
}
|
|
2930
2905
|
async embed(text, options) {
|
|
2931
|
-
var
|
|
2932
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2906
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2907
|
+
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";
|
|
2933
2908
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2934
|
-
const client = baseURL !== ((
|
|
2909
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2935
2910
|
let prompt = text;
|
|
2936
2911
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2937
2912
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -3030,9 +3005,9 @@ var GeminiProvider = class {
|
|
|
3030
3005
|
static getHealthChecker() {
|
|
3031
3006
|
return {
|
|
3032
3007
|
async check(config) {
|
|
3033
|
-
var
|
|
3008
|
+
var _a2, _b;
|
|
3034
3009
|
const timestamp = Date.now();
|
|
3035
|
-
const apiKey = (_b = (
|
|
3010
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
3036
3011
|
const modelName = sanitizeModel(config.model);
|
|
3037
3012
|
try {
|
|
3038
3013
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -3062,16 +3037,16 @@ var GeminiProvider = class {
|
|
|
3062
3037
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
3063
3038
|
* API key differs from the LLM API key. */
|
|
3064
3039
|
get embeddingClient() {
|
|
3065
|
-
var
|
|
3066
|
-
if (((
|
|
3040
|
+
var _a2;
|
|
3041
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
3067
3042
|
return buildClient(this.embeddingConfig.apiKey);
|
|
3068
3043
|
}
|
|
3069
3044
|
return this.client;
|
|
3070
3045
|
}
|
|
3071
3046
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
3072
3047
|
resolveEmbeddingModel(optionsModel) {
|
|
3073
|
-
var
|
|
3074
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3048
|
+
var _a2, _b;
|
|
3049
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
3075
3050
|
}
|
|
3076
3051
|
/**
|
|
3077
3052
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3091,8 +3066,8 @@ var GeminiProvider = class {
|
|
|
3091
3066
|
// ILLMProvider — chat
|
|
3092
3067
|
// -------------------------------------------------------------------------
|
|
3093
3068
|
async chat(messages, context, options) {
|
|
3094
|
-
var
|
|
3095
|
-
const basePrompt = (_b = (
|
|
3069
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3070
|
+
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.";
|
|
3096
3071
|
const model = this.client.getGenerativeModel({
|
|
3097
3072
|
model: this.llmConfig.model,
|
|
3098
3073
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3109,8 +3084,8 @@ var GeminiProvider = class {
|
|
|
3109
3084
|
}
|
|
3110
3085
|
chatStream(messages, context, options) {
|
|
3111
3086
|
return __asyncGenerator(this, null, function* () {
|
|
3112
|
-
var
|
|
3113
|
-
const basePrompt = (_b = (
|
|
3087
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3088
|
+
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.";
|
|
3114
3089
|
const model = this.client.getGenerativeModel({
|
|
3115
3090
|
model: this.llmConfig.model,
|
|
3116
3091
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3145,11 +3120,11 @@ var GeminiProvider = class {
|
|
|
3145
3120
|
// ILLMProvider — embeddings
|
|
3146
3121
|
// -------------------------------------------------------------------------
|
|
3147
3122
|
async embed(text, options) {
|
|
3148
|
-
var
|
|
3123
|
+
var _a2, _b;
|
|
3149
3124
|
const content = applyPrefix(
|
|
3150
3125
|
text,
|
|
3151
3126
|
options == null ? void 0 : options.taskType,
|
|
3152
|
-
(
|
|
3127
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3153
3128
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3154
3129
|
);
|
|
3155
3130
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3166,7 +3141,7 @@ var GeminiProvider = class {
|
|
|
3166
3141
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3167
3142
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3168
3143
|
const requests = texts.map((text) => {
|
|
3169
|
-
var
|
|
3144
|
+
var _a2, _b;
|
|
3170
3145
|
return {
|
|
3171
3146
|
content: {
|
|
3172
3147
|
role: "user",
|
|
@@ -3174,7 +3149,7 @@ var GeminiProvider = class {
|
|
|
3174
3149
|
text: applyPrefix(
|
|
3175
3150
|
text,
|
|
3176
3151
|
options == null ? void 0 : options.taskType,
|
|
3177
|
-
(
|
|
3152
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3178
3153
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3179
3154
|
)
|
|
3180
3155
|
}]
|
|
@@ -3191,8 +3166,8 @@ var GeminiProvider = class {
|
|
|
3191
3166
|
throw err;
|
|
3192
3167
|
});
|
|
3193
3168
|
return response.embeddings.map((e) => {
|
|
3194
|
-
var
|
|
3195
|
-
return (
|
|
3169
|
+
var _a2;
|
|
3170
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3196
3171
|
});
|
|
3197
3172
|
}
|
|
3198
3173
|
// -------------------------------------------------------------------------
|
|
@@ -3212,169 +3187,488 @@ var GeminiProvider = class {
|
|
|
3212
3187
|
}
|
|
3213
3188
|
};
|
|
3214
3189
|
|
|
3215
|
-
// src/llm/providers/
|
|
3216
|
-
var
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3226
|
-
};
|
|
3227
|
-
var LLM_PROFILES = {
|
|
3228
|
-
"openai-compatible": OPENAI_BASE,
|
|
3229
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3230
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3231
|
-
}),
|
|
3232
|
-
"anthropic-claude": {
|
|
3233
|
-
chatPath: "/v1/messages",
|
|
3234
|
-
responseExtractPath: "content[0].text",
|
|
3235
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
3236
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3237
|
-
},
|
|
3238
|
-
"google-gemini": {
|
|
3239
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3240
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3241
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3242
|
-
},
|
|
3243
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3244
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3245
|
-
}),
|
|
3246
|
-
"ollama-standard": {
|
|
3247
|
-
chatPath: "/api/chat",
|
|
3248
|
-
embedPath: "/api/embeddings",
|
|
3249
|
-
responseExtractPath: "message.content",
|
|
3250
|
-
embedExtractPath: "embedding",
|
|
3251
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3252
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3253
|
-
}
|
|
3254
|
-
};
|
|
3255
|
-
|
|
3256
|
-
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3257
|
-
var UniversalLLMAdapter = class {
|
|
3258
|
-
constructor(config) {
|
|
3259
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3260
|
-
this.model = config.model;
|
|
3261
|
-
const llmConfig = config;
|
|
3262
|
-
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
3263
|
-
let profile = {};
|
|
3264
|
-
if (typeof options.profile === "string") {
|
|
3265
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
3266
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3267
|
-
profile = options.profile;
|
|
3268
|
-
}
|
|
3269
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3270
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3271
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3272
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3273
|
-
this.apiKey = config.apiKey;
|
|
3274
|
-
this.baseUrl = (_g = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g : "";
|
|
3275
|
-
if (!this.baseUrl) {
|
|
3276
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3277
|
-
}
|
|
3278
|
-
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3279
|
-
"Content-Type": "application/json"
|
|
3280
|
-
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3281
|
-
this.http = import_axios2.default.create({
|
|
3282
|
-
baseURL: this.baseUrl,
|
|
3283
|
-
headers: this.resolvedHeaders,
|
|
3284
|
-
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3190
|
+
// src/llm/providers/GroqProvider.ts
|
|
3191
|
+
var import_openai2 = __toESM(require("openai"));
|
|
3192
|
+
var GroqProvider = class {
|
|
3193
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3194
|
+
void embeddingConfig;
|
|
3195
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3196
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3197
|
+
this.client = new import_openai2.default({
|
|
3198
|
+
apiKey,
|
|
3199
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3285
3200
|
});
|
|
3201
|
+
this.llmConfig = llmConfig;
|
|
3286
3202
|
}
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3203
|
+
static getValidator() {
|
|
3204
|
+
return {
|
|
3205
|
+
validate(config) {
|
|
3206
|
+
const errors = [];
|
|
3207
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3208
|
+
errors.push({
|
|
3209
|
+
field: "llm.apiKey",
|
|
3210
|
+
message: "Groq API key is required",
|
|
3211
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3212
|
+
severity: "error"
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
if (!config.model) {
|
|
3216
|
+
errors.push({
|
|
3217
|
+
field: "llm.model",
|
|
3218
|
+
message: "Groq model name is required",
|
|
3219
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3220
|
+
severity: "error"
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
return errors;
|
|
3224
|
+
}
|
|
3225
|
+
};
|
|
3226
|
+
}
|
|
3227
|
+
static getHealthChecker() {
|
|
3228
|
+
return {
|
|
3229
|
+
async check(config) {
|
|
3230
|
+
const timestamp = Date.now();
|
|
3231
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3232
|
+
const modelName = config.model;
|
|
3233
|
+
try {
|
|
3234
|
+
const OpenAI4 = await import("openai");
|
|
3235
|
+
const client = new OpenAI4.default({
|
|
3236
|
+
apiKey,
|
|
3237
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3238
|
+
});
|
|
3239
|
+
const models = await client.models.list();
|
|
3240
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3241
|
+
return {
|
|
3242
|
+
healthy: true,
|
|
3243
|
+
provider: "groq",
|
|
3244
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3245
|
+
timestamp
|
|
3246
|
+
};
|
|
3247
|
+
} catch (error) {
|
|
3248
|
+
return {
|
|
3249
|
+
healthy: false,
|
|
3250
|
+
provider: "groq",
|
|
3251
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3252
|
+
timestamp
|
|
3253
|
+
};
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
};
|
|
3257
|
+
}
|
|
3258
|
+
async chat(messages, context, options) {
|
|
3259
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3260
|
+
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.";
|
|
3261
|
+
const systemMessage = {
|
|
3262
|
+
role: "system",
|
|
3263
|
+
content: buildSystemContent(basePrompt, context)
|
|
3264
|
+
};
|
|
3290
3265
|
const formattedMessages = [
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3266
|
+
systemMessage,
|
|
3267
|
+
...messages.map((m) => ({
|
|
3268
|
+
role: m.role,
|
|
3269
|
+
content: m.content
|
|
3270
|
+
}))
|
|
3296
3271
|
];
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
} else {
|
|
3306
|
-
payload = {
|
|
3307
|
-
model: this.model,
|
|
3308
|
-
messages: formattedMessages,
|
|
3309
|
-
max_tokens: this.maxTokens,
|
|
3310
|
-
temperature: this.temperature
|
|
3311
|
-
};
|
|
3312
|
-
}
|
|
3313
|
-
const { data } = await this.http.post(path, payload);
|
|
3314
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3315
|
-
const result = resolvePath(data, extractPath);
|
|
3316
|
-
if (result === void 0) {
|
|
3317
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3318
|
-
}
|
|
3319
|
-
return String(result);
|
|
3272
|
+
const completion = await this.client.chat.completions.create({
|
|
3273
|
+
model: this.llmConfig.model,
|
|
3274
|
+
messages: formattedMessages,
|
|
3275
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3276
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3277
|
+
stop: options == null ? void 0 : options.stop
|
|
3278
|
+
});
|
|
3279
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3320
3280
|
}
|
|
3321
|
-
|
|
3322
|
-
* Streaming chat using native fetch + ReadableStream.
|
|
3323
|
-
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3324
|
-
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3325
|
-
*/
|
|
3326
|
-
chatStream(messages, context) {
|
|
3281
|
+
chatStream(messages, context, options) {
|
|
3327
3282
|
return __asyncGenerator(this, null, function* () {
|
|
3328
|
-
var
|
|
3329
|
-
const
|
|
3330
|
-
const
|
|
3331
|
-
|
|
3283
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3284
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3285
|
+
const systemMessage = {
|
|
3286
|
+
role: "system",
|
|
3287
|
+
content: buildSystemContent(basePrompt, context)
|
|
3288
|
+
};
|
|
3332
3289
|
const formattedMessages = [
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3290
|
+
systemMessage,
|
|
3291
|
+
...messages.map((m) => ({
|
|
3292
|
+
role: m.role,
|
|
3293
|
+
content: m.content
|
|
3294
|
+
}))
|
|
3338
3295
|
];
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
});
|
|
3347
|
-
if (typeof payload === "object" && payload !== null) {
|
|
3348
|
-
payload.stream = true;
|
|
3349
|
-
}
|
|
3350
|
-
} else {
|
|
3351
|
-
payload = {
|
|
3352
|
-
model: this.model,
|
|
3353
|
-
messages: formattedMessages,
|
|
3354
|
-
max_tokens: this.maxTokens,
|
|
3355
|
-
temperature: this.temperature,
|
|
3356
|
-
stream: true
|
|
3357
|
-
};
|
|
3358
|
-
}
|
|
3359
|
-
const response = yield new __await(fetch(url, {
|
|
3360
|
-
method: "POST",
|
|
3361
|
-
headers: this.resolvedHeaders,
|
|
3362
|
-
body: JSON.stringify(payload)
|
|
3296
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3297
|
+
model: this.llmConfig.model,
|
|
3298
|
+
messages: formattedMessages,
|
|
3299
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3300
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3301
|
+
stop: options == null ? void 0 : options.stop,
|
|
3302
|
+
stream: true
|
|
3363
3303
|
}));
|
|
3364
|
-
if (!
|
|
3365
|
-
|
|
3366
|
-
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3367
|
-
}
|
|
3368
|
-
if (!response.body) {
|
|
3369
|
-
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3304
|
+
if (!stream) {
|
|
3305
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3370
3306
|
}
|
|
3371
|
-
const reader = response.body.getReader();
|
|
3372
|
-
const decoder = new TextDecoder("utf-8");
|
|
3373
|
-
let buffer = "";
|
|
3374
3307
|
try {
|
|
3375
|
-
|
|
3376
|
-
const
|
|
3377
|
-
|
|
3308
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3309
|
+
const chunk = temp.value;
|
|
3310
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3311
|
+
if (content) yield content;
|
|
3312
|
+
}
|
|
3313
|
+
} catch (temp) {
|
|
3314
|
+
error = [temp];
|
|
3315
|
+
} finally {
|
|
3316
|
+
try {
|
|
3317
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3318
|
+
} finally {
|
|
3319
|
+
if (error)
|
|
3320
|
+
throw error[0];
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
async embed(text, options) {
|
|
3326
|
+
void text;
|
|
3327
|
+
void options;
|
|
3328
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3329
|
+
}
|
|
3330
|
+
async batchEmbed(texts, options) {
|
|
3331
|
+
void texts;
|
|
3332
|
+
void options;
|
|
3333
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3334
|
+
}
|
|
3335
|
+
async ping() {
|
|
3336
|
+
try {
|
|
3337
|
+
await this.client.models.list();
|
|
3338
|
+
return true;
|
|
3339
|
+
} catch (err) {
|
|
3340
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3341
|
+
return false;
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
};
|
|
3345
|
+
|
|
3346
|
+
// src/llm/providers/QwenProvider.ts
|
|
3347
|
+
var import_openai3 = __toESM(require("openai"));
|
|
3348
|
+
var QwenProvider = class {
|
|
3349
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3350
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3351
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3352
|
+
this.client = new import_openai3.default({
|
|
3353
|
+
apiKey,
|
|
3354
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3355
|
+
});
|
|
3356
|
+
this.llmConfig = llmConfig;
|
|
3357
|
+
this.embeddingConfig = embeddingConfig;
|
|
3358
|
+
}
|
|
3359
|
+
static getValidator() {
|
|
3360
|
+
return {
|
|
3361
|
+
validate(config) {
|
|
3362
|
+
const errors = [];
|
|
3363
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3364
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3365
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3366
|
+
errors.push({
|
|
3367
|
+
field: `${prefix}.apiKey`,
|
|
3368
|
+
message: "Qwen API key is required",
|
|
3369
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3370
|
+
severity: "error"
|
|
3371
|
+
});
|
|
3372
|
+
}
|
|
3373
|
+
if (!config.model) {
|
|
3374
|
+
errors.push({
|
|
3375
|
+
field: `${prefix}.model`,
|
|
3376
|
+
message: "Qwen model name is required",
|
|
3377
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3378
|
+
severity: "error"
|
|
3379
|
+
});
|
|
3380
|
+
}
|
|
3381
|
+
return errors;
|
|
3382
|
+
}
|
|
3383
|
+
};
|
|
3384
|
+
}
|
|
3385
|
+
static getHealthChecker() {
|
|
3386
|
+
return {
|
|
3387
|
+
async check(config) {
|
|
3388
|
+
const timestamp = Date.now();
|
|
3389
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3390
|
+
const modelName = config.model;
|
|
3391
|
+
try {
|
|
3392
|
+
const OpenAI4 = await import("openai");
|
|
3393
|
+
const client = new OpenAI4.default({
|
|
3394
|
+
apiKey,
|
|
3395
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3396
|
+
});
|
|
3397
|
+
const models = await client.models.list();
|
|
3398
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3399
|
+
return {
|
|
3400
|
+
healthy: true,
|
|
3401
|
+
provider: "qwen",
|
|
3402
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3403
|
+
timestamp
|
|
3404
|
+
};
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
return {
|
|
3407
|
+
healthy: false,
|
|
3408
|
+
provider: "qwen",
|
|
3409
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3410
|
+
timestamp
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
async chat(messages, context, options) {
|
|
3417
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3418
|
+
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.";
|
|
3419
|
+
const systemMessage = {
|
|
3420
|
+
role: "system",
|
|
3421
|
+
content: buildSystemContent(basePrompt, context)
|
|
3422
|
+
};
|
|
3423
|
+
const formattedMessages = [
|
|
3424
|
+
systemMessage,
|
|
3425
|
+
...messages.map((m) => ({
|
|
3426
|
+
role: m.role,
|
|
3427
|
+
content: m.content
|
|
3428
|
+
}))
|
|
3429
|
+
];
|
|
3430
|
+
const completion = await this.client.chat.completions.create({
|
|
3431
|
+
model: this.llmConfig.model,
|
|
3432
|
+
messages: formattedMessages,
|
|
3433
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3434
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3435
|
+
stop: options == null ? void 0 : options.stop
|
|
3436
|
+
});
|
|
3437
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3438
|
+
}
|
|
3439
|
+
chatStream(messages, context, options) {
|
|
3440
|
+
return __asyncGenerator(this, null, function* () {
|
|
3441
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3442
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3443
|
+
const systemMessage = {
|
|
3444
|
+
role: "system",
|
|
3445
|
+
content: buildSystemContent(basePrompt, context)
|
|
3446
|
+
};
|
|
3447
|
+
const formattedMessages = [
|
|
3448
|
+
systemMessage,
|
|
3449
|
+
...messages.map((m) => ({
|
|
3450
|
+
role: m.role,
|
|
3451
|
+
content: m.content
|
|
3452
|
+
}))
|
|
3453
|
+
];
|
|
3454
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3455
|
+
model: this.llmConfig.model,
|
|
3456
|
+
messages: formattedMessages,
|
|
3457
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3458
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3459
|
+
stop: options == null ? void 0 : options.stop,
|
|
3460
|
+
stream: true
|
|
3461
|
+
}));
|
|
3462
|
+
if (!stream) {
|
|
3463
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3464
|
+
}
|
|
3465
|
+
try {
|
|
3466
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3467
|
+
const chunk = temp.value;
|
|
3468
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3469
|
+
if (content) yield content;
|
|
3470
|
+
}
|
|
3471
|
+
} catch (temp) {
|
|
3472
|
+
error = [temp];
|
|
3473
|
+
} finally {
|
|
3474
|
+
try {
|
|
3475
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3476
|
+
} finally {
|
|
3477
|
+
if (error)
|
|
3478
|
+
throw error[0];
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
async embed(text, options) {
|
|
3484
|
+
const results = await this.batchEmbed([text], options);
|
|
3485
|
+
return results[0];
|
|
3486
|
+
}
|
|
3487
|
+
async batchEmbed(texts, options) {
|
|
3488
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3489
|
+
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";
|
|
3490
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3491
|
+
const client = apiKey !== this.llmConfig.apiKey ? new import_openai3.default({
|
|
3492
|
+
apiKey,
|
|
3493
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3494
|
+
}) : this.client;
|
|
3495
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3496
|
+
return response.data.map((d) => d.embedding);
|
|
3497
|
+
}
|
|
3498
|
+
async ping() {
|
|
3499
|
+
try {
|
|
3500
|
+
await this.client.models.list();
|
|
3501
|
+
return true;
|
|
3502
|
+
} catch (err) {
|
|
3503
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3504
|
+
return false;
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
|
|
3509
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3510
|
+
var import_axios2 = __toESM(require("axios"));
|
|
3511
|
+
init_templateUtils();
|
|
3512
|
+
|
|
3513
|
+
// src/config/UniversalProfiles.ts
|
|
3514
|
+
var OPENAI_BASE = {
|
|
3515
|
+
chatPath: "/chat/completions",
|
|
3516
|
+
embedPath: "/embeddings",
|
|
3517
|
+
responseExtractPath: "choices[0].message.content",
|
|
3518
|
+
embedExtractPath: "data[0].embedding",
|
|
3519
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3520
|
+
};
|
|
3521
|
+
var LLM_PROFILES = {
|
|
3522
|
+
"openai-compatible": OPENAI_BASE,
|
|
3523
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3524
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3525
|
+
}),
|
|
3526
|
+
"anthropic-claude": {
|
|
3527
|
+
chatPath: "/v1/messages",
|
|
3528
|
+
responseExtractPath: "content[0].text",
|
|
3529
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
3530
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3531
|
+
},
|
|
3532
|
+
"google-gemini": {
|
|
3533
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3534
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3535
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3536
|
+
},
|
|
3537
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3538
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3539
|
+
}),
|
|
3540
|
+
"ollama-standard": {
|
|
3541
|
+
chatPath: "/api/chat",
|
|
3542
|
+
embedPath: "/api/embeddings",
|
|
3543
|
+
responseExtractPath: "message.content",
|
|
3544
|
+
embedExtractPath: "embedding",
|
|
3545
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3546
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3547
|
+
}
|
|
3548
|
+
};
|
|
3549
|
+
|
|
3550
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3551
|
+
var UniversalLLMAdapter = class {
|
|
3552
|
+
constructor(config) {
|
|
3553
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3554
|
+
this.model = config.model;
|
|
3555
|
+
const llmConfig = config;
|
|
3556
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3557
|
+
let profile = {};
|
|
3558
|
+
if (typeof options.profile === "string") {
|
|
3559
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
3560
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3561
|
+
profile = options.profile;
|
|
3562
|
+
}
|
|
3563
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3564
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3565
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3566
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3567
|
+
this.apiKey = config.apiKey;
|
|
3568
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3569
|
+
if (!this.baseUrl) {
|
|
3570
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3571
|
+
}
|
|
3572
|
+
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3573
|
+
"Content-Type": "application/json"
|
|
3574
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3575
|
+
this.http = import_axios2.default.create({
|
|
3576
|
+
baseURL: this.baseUrl,
|
|
3577
|
+
headers: this.resolvedHeaders,
|
|
3578
|
+
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3579
|
+
});
|
|
3580
|
+
}
|
|
3581
|
+
async chat(messages, context) {
|
|
3582
|
+
var _a2, _b;
|
|
3583
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3584
|
+
const formattedMessages = [
|
|
3585
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3586
|
+
|
|
3587
|
+
Context:
|
|
3588
|
+
${context != null ? context : "None"}` },
|
|
3589
|
+
...messages
|
|
3590
|
+
];
|
|
3591
|
+
let payload;
|
|
3592
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3593
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3594
|
+
model: this.model,
|
|
3595
|
+
messages: formattedMessages,
|
|
3596
|
+
maxTokens: this.maxTokens,
|
|
3597
|
+
temperature: this.temperature
|
|
3598
|
+
});
|
|
3599
|
+
} else {
|
|
3600
|
+
payload = {
|
|
3601
|
+
model: this.model,
|
|
3602
|
+
messages: formattedMessages,
|
|
3603
|
+
max_tokens: this.maxTokens,
|
|
3604
|
+
temperature: this.temperature
|
|
3605
|
+
};
|
|
3606
|
+
}
|
|
3607
|
+
const { data } = await this.http.post(path2, payload);
|
|
3608
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3609
|
+
const result = resolvePath(data, extractPath);
|
|
3610
|
+
if (result === void 0) {
|
|
3611
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3612
|
+
}
|
|
3613
|
+
return String(result);
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Streaming chat using native fetch + ReadableStream.
|
|
3617
|
+
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3618
|
+
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3619
|
+
*/
|
|
3620
|
+
chatStream(messages, context) {
|
|
3621
|
+
return __asyncGenerator(this, null, function* () {
|
|
3622
|
+
var _a2, _b, _c;
|
|
3623
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3624
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3625
|
+
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3626
|
+
const formattedMessages = [
|
|
3627
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3628
|
+
|
|
3629
|
+
Context:
|
|
3630
|
+
${context != null ? context : "None"}` },
|
|
3631
|
+
...messages
|
|
3632
|
+
];
|
|
3633
|
+
let payload;
|
|
3634
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3635
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3636
|
+
model: this.model,
|
|
3637
|
+
messages: formattedMessages,
|
|
3638
|
+
maxTokens: this.maxTokens,
|
|
3639
|
+
temperature: this.temperature
|
|
3640
|
+
});
|
|
3641
|
+
if (typeof payload === "object" && payload !== null) {
|
|
3642
|
+
payload.stream = true;
|
|
3643
|
+
}
|
|
3644
|
+
} else {
|
|
3645
|
+
payload = {
|
|
3646
|
+
model: this.model,
|
|
3647
|
+
messages: formattedMessages,
|
|
3648
|
+
max_tokens: this.maxTokens,
|
|
3649
|
+
temperature: this.temperature,
|
|
3650
|
+
stream: true
|
|
3651
|
+
};
|
|
3652
|
+
}
|
|
3653
|
+
const response = yield new __await(fetch(url, {
|
|
3654
|
+
method: "POST",
|
|
3655
|
+
headers: this.resolvedHeaders,
|
|
3656
|
+
body: JSON.stringify(payload)
|
|
3657
|
+
}));
|
|
3658
|
+
if (!response.ok) {
|
|
3659
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
3660
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3661
|
+
}
|
|
3662
|
+
if (!response.body) {
|
|
3663
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3664
|
+
}
|
|
3665
|
+
const reader = response.body.getReader();
|
|
3666
|
+
const decoder = new TextDecoder("utf-8");
|
|
3667
|
+
let buffer = "";
|
|
3668
|
+
try {
|
|
3669
|
+
while (true) {
|
|
3670
|
+
const { done, value } = yield new __await(reader.read());
|
|
3671
|
+
if (done) break;
|
|
3378
3672
|
buffer += decoder.decode(value, { stream: true });
|
|
3379
3673
|
const lines = buffer.split("\n");
|
|
3380
3674
|
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
@@ -3405,8 +3699,8 @@ ${context != null ? context : "None"}` },
|
|
|
3405
3699
|
});
|
|
3406
3700
|
}
|
|
3407
3701
|
async embed(text) {
|
|
3408
|
-
var
|
|
3409
|
-
const
|
|
3702
|
+
var _a2, _b;
|
|
3703
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3410
3704
|
let payload;
|
|
3411
3705
|
if (this.opts.embedPayloadTemplate) {
|
|
3412
3706
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3419,7 +3713,7 @@ ${context != null ? context : "None"}` },
|
|
|
3419
3713
|
input: text
|
|
3420
3714
|
};
|
|
3421
3715
|
}
|
|
3422
|
-
const { data } = await this.http.post(
|
|
3716
|
+
const { data } = await this.http.post(path2, payload);
|
|
3423
3717
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3424
3718
|
const vector = resolvePath(data, extractPath);
|
|
3425
3719
|
if (!Array.isArray(vector)) {
|
|
@@ -3447,6 +3741,78 @@ ${context != null ? context : "None"}` },
|
|
|
3447
3741
|
}
|
|
3448
3742
|
};
|
|
3449
3743
|
|
|
3744
|
+
// src/exceptions/index.ts
|
|
3745
|
+
var RetrivoraError = class extends Error {
|
|
3746
|
+
constructor(message, code, details) {
|
|
3747
|
+
super(message);
|
|
3748
|
+
this.name = new.target.name;
|
|
3749
|
+
this.code = code;
|
|
3750
|
+
this.details = details;
|
|
3751
|
+
}
|
|
3752
|
+
};
|
|
3753
|
+
var ProviderNotFoundException = class extends RetrivoraError {
|
|
3754
|
+
constructor(providerType, provider, details) {
|
|
3755
|
+
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
3756
|
+
}
|
|
3757
|
+
};
|
|
3758
|
+
var EmbeddingFailedException = class extends RetrivoraError {
|
|
3759
|
+
constructor(message = "Embedding generation failed", details) {
|
|
3760
|
+
super(message, "EMBEDDING_FAILED", details);
|
|
3761
|
+
}
|
|
3762
|
+
};
|
|
3763
|
+
var RetrievalException = class extends RetrivoraError {
|
|
3764
|
+
constructor(message = "Retrieval failed", details) {
|
|
3765
|
+
super(message, "RETRIEVAL_FAILED", details);
|
|
3766
|
+
}
|
|
3767
|
+
};
|
|
3768
|
+
var RateLimitException = class extends RetrivoraError {
|
|
3769
|
+
constructor(message = "Provider rate limit exceeded", details) {
|
|
3770
|
+
super(message, "RATE_LIMITED", details);
|
|
3771
|
+
}
|
|
3772
|
+
};
|
|
3773
|
+
var ConfigurationException = class extends RetrivoraError {
|
|
3774
|
+
constructor(message, details) {
|
|
3775
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
3776
|
+
}
|
|
3777
|
+
};
|
|
3778
|
+
var AuthenticationException = class extends RetrivoraError {
|
|
3779
|
+
constructor(message = "Provider authentication failed", details) {
|
|
3780
|
+
super(message, "AUTHENTICATION_ERROR", details);
|
|
3781
|
+
}
|
|
3782
|
+
};
|
|
3783
|
+
function wrapError(err, defaultCode, defaultMessage) {
|
|
3784
|
+
var _a2;
|
|
3785
|
+
if (err instanceof RetrivoraError) {
|
|
3786
|
+
return err;
|
|
3787
|
+
}
|
|
3788
|
+
const error = err;
|
|
3789
|
+
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3790
|
+
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);
|
|
3791
|
+
const code = error == null ? void 0 : error.code;
|
|
3792
|
+
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3793
|
+
return new RateLimitException(message, err);
|
|
3794
|
+
}
|
|
3795
|
+
if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
|
|
3796
|
+
return new AuthenticationException(message, err);
|
|
3797
|
+
}
|
|
3798
|
+
switch (defaultCode) {
|
|
3799
|
+
case "PROVIDER_NOT_FOUND":
|
|
3800
|
+
return new ProviderNotFoundException("provider", message, err);
|
|
3801
|
+
case "EMBEDDING_FAILED":
|
|
3802
|
+
return new EmbeddingFailedException(message, err);
|
|
3803
|
+
case "RETRIEVAL_FAILED":
|
|
3804
|
+
return new RetrievalException(message, err);
|
|
3805
|
+
case "RATE_LIMITED":
|
|
3806
|
+
return new RateLimitException(message, err);
|
|
3807
|
+
case "CONFIGURATION_ERROR":
|
|
3808
|
+
return new ConfigurationException(message, err);
|
|
3809
|
+
case "AUTHENTICATION_ERROR":
|
|
3810
|
+
return new AuthenticationException(message, err);
|
|
3811
|
+
default:
|
|
3812
|
+
return new RetrivoraError(message, defaultCode, err);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
|
|
3450
3816
|
// src/llm/LLMFactory.ts
|
|
3451
3817
|
var customProviders = /* @__PURE__ */ new Map();
|
|
3452
3818
|
var LLMFactory = class _LLMFactory {
|
|
@@ -3485,6 +3851,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3485
3851
|
"anthropic",
|
|
3486
3852
|
"ollama",
|
|
3487
3853
|
"gemini",
|
|
3854
|
+
"groq",
|
|
3855
|
+
"qwen",
|
|
3488
3856
|
"rest",
|
|
3489
3857
|
"universal_rest",
|
|
3490
3858
|
"custom",
|
|
@@ -3492,7 +3860,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3492
3860
|
];
|
|
3493
3861
|
}
|
|
3494
3862
|
static create(llmConfig, embeddingConfig) {
|
|
3495
|
-
var
|
|
3863
|
+
var _a2, _b, _c;
|
|
3496
3864
|
switch (llmConfig.provider) {
|
|
3497
3865
|
case "openai":
|
|
3498
3866
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3502,12 +3870,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3502
3870
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3503
3871
|
case "gemini":
|
|
3504
3872
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3873
|
+
case "groq":
|
|
3874
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3875
|
+
case "qwen":
|
|
3876
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3505
3877
|
case "rest":
|
|
3506
3878
|
case "universal_rest":
|
|
3507
3879
|
case "custom":
|
|
3508
3880
|
return new UniversalLLMAdapter(llmConfig);
|
|
3509
3881
|
default: {
|
|
3510
|
-
const providerName = String((
|
|
3882
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3511
3883
|
const customFactory = customProviders.get(providerName);
|
|
3512
3884
|
if (customFactory) {
|
|
3513
3885
|
return customFactory(llmConfig);
|
|
@@ -3516,9 +3888,12 @@ var LLMFactory = class _LLMFactory {
|
|
|
3516
3888
|
return new UniversalLLMAdapter(llmConfig);
|
|
3517
3889
|
}
|
|
3518
3890
|
throw new ProviderNotFoundException(
|
|
3519
|
-
"
|
|
3520
|
-
|
|
3521
|
-
|
|
3891
|
+
"llm",
|
|
3892
|
+
(_c = llmConfig.provider) != null ? _c : "undefined",
|
|
3893
|
+
{
|
|
3894
|
+
message: `Unknown provider "${llmConfig.provider}". Register a custom provider with LLMFactory.register().`,
|
|
3895
|
+
available: _LLMFactory.listProviders()
|
|
3896
|
+
}
|
|
3522
3897
|
);
|
|
3523
3898
|
}
|
|
3524
3899
|
}
|
|
@@ -3541,6 +3916,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3541
3916
|
return OllamaProvider;
|
|
3542
3917
|
case "gemini":
|
|
3543
3918
|
return GeminiProvider;
|
|
3919
|
+
case "groq":
|
|
3920
|
+
return GroqProvider;
|
|
3921
|
+
case "qwen":
|
|
3922
|
+
return QwenProvider;
|
|
3544
3923
|
case "rest":
|
|
3545
3924
|
case "universal_rest":
|
|
3546
3925
|
case "custom":
|
|
@@ -3602,7 +3981,7 @@ var ProviderRegistry = class {
|
|
|
3602
3981
|
return null;
|
|
3603
3982
|
}
|
|
3604
3983
|
static async loadVectorProviderClass(provider) {
|
|
3605
|
-
var
|
|
3984
|
+
var _a2;
|
|
3606
3985
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3607
3986
|
switch (provider) {
|
|
3608
3987
|
case "pinecone": {
|
|
@@ -3611,7 +3990,7 @@ var ProviderRegistry = class {
|
|
|
3611
3990
|
}
|
|
3612
3991
|
case "pgvector":
|
|
3613
3992
|
case "postgresql": {
|
|
3614
|
-
const postgresMode = ((
|
|
3993
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3615
3994
|
if (postgresMode === "single") {
|
|
3616
3995
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3617
3996
|
return PostgreSQLProvider2;
|
|
@@ -4060,11 +4439,11 @@ var LlamaIndexIngestor = class {
|
|
|
4060
4439
|
* than standard character-count splitting.
|
|
4061
4440
|
*/
|
|
4062
4441
|
async chunk(text, options = {}) {
|
|
4063
|
-
var
|
|
4442
|
+
var _a2, _b;
|
|
4064
4443
|
try {
|
|
4065
4444
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4066
4445
|
const splitter = new SentenceSplitter({
|
|
4067
|
-
chunkSize: (
|
|
4446
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4068
4447
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4069
4448
|
});
|
|
4070
4449
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4173,7 +4552,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4173
4552
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4174
4553
|
*/
|
|
4175
4554
|
async run(input, chatHistory = []) {
|
|
4176
|
-
var
|
|
4555
|
+
var _a2, _b, _c;
|
|
4177
4556
|
if (!this.agent) {
|
|
4178
4557
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4179
4558
|
}
|
|
@@ -4184,7 +4563,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4184
4563
|
const response = await this.agent.invoke({
|
|
4185
4564
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4186
4565
|
});
|
|
4187
|
-
const lastMessage = (
|
|
4566
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4188
4567
|
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4189
4568
|
return lastMessage.content;
|
|
4190
4569
|
}
|
|
@@ -4195,6 +4574,437 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4195
4574
|
}
|
|
4196
4575
|
};
|
|
4197
4576
|
|
|
4577
|
+
// src/core/mcp.ts
|
|
4578
|
+
var import_child_process = require("child_process");
|
|
4579
|
+
var MCPClient = class {
|
|
4580
|
+
constructor(config) {
|
|
4581
|
+
this.config = config;
|
|
4582
|
+
this.messageIdCounter = 0;
|
|
4583
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4584
|
+
this.stdioBuffer = "";
|
|
4585
|
+
this.initialized = false;
|
|
4586
|
+
}
|
|
4587
|
+
getNextMessageId() {
|
|
4588
|
+
return ++this.messageIdCounter;
|
|
4589
|
+
}
|
|
4590
|
+
/**
|
|
4591
|
+
* Connect and initialize the MCP server connection.
|
|
4592
|
+
*/
|
|
4593
|
+
async connect() {
|
|
4594
|
+
if (this.initialized) return;
|
|
4595
|
+
if (this.config.transport === "stdio") {
|
|
4596
|
+
await this.connectStdio();
|
|
4597
|
+
} else {
|
|
4598
|
+
await this.connectSSE();
|
|
4599
|
+
}
|
|
4600
|
+
try {
|
|
4601
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4602
|
+
protocolVersion: "2024-11-05",
|
|
4603
|
+
capabilities: {},
|
|
4604
|
+
clientInfo: {
|
|
4605
|
+
name: "retrivora-sdk",
|
|
4606
|
+
version: "1.0.0"
|
|
4607
|
+
}
|
|
4608
|
+
});
|
|
4609
|
+
await this.sendNotification("notifications/initialized");
|
|
4610
|
+
this.initialized = true;
|
|
4611
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4612
|
+
} catch (err) {
|
|
4613
|
+
this.disconnect();
|
|
4614
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
async connectStdio() {
|
|
4618
|
+
var _a2;
|
|
4619
|
+
const cmd = this.config.command;
|
|
4620
|
+
if (!cmd) {
|
|
4621
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4622
|
+
}
|
|
4623
|
+
const args = this.config.args || [];
|
|
4624
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4625
|
+
this.childProcess = (0, import_child_process.spawn)(cmd, args, { env, shell: true });
|
|
4626
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4627
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4628
|
+
}
|
|
4629
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4630
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4631
|
+
this.processStdioLines();
|
|
4632
|
+
});
|
|
4633
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4634
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4635
|
+
});
|
|
4636
|
+
this.childProcess.on("close", (code) => {
|
|
4637
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4638
|
+
this.disconnect();
|
|
4639
|
+
});
|
|
4640
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4641
|
+
}
|
|
4642
|
+
processStdioLines() {
|
|
4643
|
+
let newlineIndex;
|
|
4644
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4645
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4646
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4647
|
+
if (!line) continue;
|
|
4648
|
+
try {
|
|
4649
|
+
const payload = JSON.parse(line);
|
|
4650
|
+
if (payload.id !== void 0) {
|
|
4651
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4652
|
+
if (req) {
|
|
4653
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4654
|
+
if (payload.error) {
|
|
4655
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4656
|
+
} else {
|
|
4657
|
+
req.resolve(payload.result);
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
} catch (e) {
|
|
4662
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
async connectSSE() {
|
|
4667
|
+
if (!this.config.url) {
|
|
4668
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4669
|
+
}
|
|
4670
|
+
this.sseUrl = this.config.url;
|
|
4671
|
+
}
|
|
4672
|
+
async sendJsonRpc(method, params) {
|
|
4673
|
+
const id = this.getNextMessageId();
|
|
4674
|
+
const request = {
|
|
4675
|
+
jsonrpc: "2.0",
|
|
4676
|
+
id,
|
|
4677
|
+
method,
|
|
4678
|
+
params
|
|
4679
|
+
};
|
|
4680
|
+
if (this.config.transport === "stdio") {
|
|
4681
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4682
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4683
|
+
}
|
|
4684
|
+
return new Promise((resolve, reject) => {
|
|
4685
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4686
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4687
|
+
});
|
|
4688
|
+
} else {
|
|
4689
|
+
if (!this.sseUrl) {
|
|
4690
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4691
|
+
}
|
|
4692
|
+
const response = await fetch(this.sseUrl, {
|
|
4693
|
+
method: "POST",
|
|
4694
|
+
headers: { "Content-Type": "application/json" },
|
|
4695
|
+
body: JSON.stringify(request)
|
|
4696
|
+
});
|
|
4697
|
+
if (!response.ok) {
|
|
4698
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4699
|
+
}
|
|
4700
|
+
const payload = await response.json();
|
|
4701
|
+
if (payload.error) {
|
|
4702
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4703
|
+
}
|
|
4704
|
+
return payload.result;
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
async sendNotification(method, params) {
|
|
4708
|
+
var _a2;
|
|
4709
|
+
const notification = {
|
|
4710
|
+
jsonrpc: "2.0",
|
|
4711
|
+
method,
|
|
4712
|
+
params
|
|
4713
|
+
};
|
|
4714
|
+
if (this.config.transport === "stdio") {
|
|
4715
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4716
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4717
|
+
}
|
|
4718
|
+
} else if (this.sseUrl) {
|
|
4719
|
+
await fetch(this.sseUrl, {
|
|
4720
|
+
method: "POST",
|
|
4721
|
+
headers: { "Content-Type": "application/json" },
|
|
4722
|
+
body: JSON.stringify(notification)
|
|
4723
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4724
|
+
}
|
|
4725
|
+
}
|
|
4726
|
+
/**
|
|
4727
|
+
* List all tools offered by the MCP server.
|
|
4728
|
+
*/
|
|
4729
|
+
async listTools() {
|
|
4730
|
+
await this.connect();
|
|
4731
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4732
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4733
|
+
}
|
|
4734
|
+
/**
|
|
4735
|
+
* Execute a tool on the MCP server.
|
|
4736
|
+
*/
|
|
4737
|
+
async callTool(name, args = {}) {
|
|
4738
|
+
await this.connect();
|
|
4739
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4740
|
+
}
|
|
4741
|
+
disconnect() {
|
|
4742
|
+
this.initialized = false;
|
|
4743
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4744
|
+
this.pendingRequests.clear();
|
|
4745
|
+
if (this.childProcess) {
|
|
4746
|
+
try {
|
|
4747
|
+
this.childProcess.kill();
|
|
4748
|
+
} catch (e) {
|
|
4749
|
+
}
|
|
4750
|
+
this.childProcess = void 0;
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
};
|
|
4754
|
+
var MCPRegistry = class {
|
|
4755
|
+
constructor(servers = []) {
|
|
4756
|
+
this.clients = [];
|
|
4757
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4758
|
+
}
|
|
4759
|
+
async getAllTools() {
|
|
4760
|
+
const list = [];
|
|
4761
|
+
await Promise.all(
|
|
4762
|
+
this.clients.map(async (client) => {
|
|
4763
|
+
try {
|
|
4764
|
+
const tools = await client.listTools();
|
|
4765
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4766
|
+
} catch (e) {
|
|
4767
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4768
|
+
}
|
|
4769
|
+
})
|
|
4770
|
+
);
|
|
4771
|
+
return list;
|
|
4772
|
+
}
|
|
4773
|
+
async callTool(toolName, args = {}) {
|
|
4774
|
+
for (const client of this.clients) {
|
|
4775
|
+
try {
|
|
4776
|
+
const tools = await client.listTools();
|
|
4777
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4778
|
+
return await client.callTool(toolName, args);
|
|
4779
|
+
}
|
|
4780
|
+
} catch (e) {
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4784
|
+
}
|
|
4785
|
+
disconnectAll() {
|
|
4786
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4787
|
+
}
|
|
4788
|
+
};
|
|
4789
|
+
|
|
4790
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4791
|
+
var MultiAgentCoordinator = class {
|
|
4792
|
+
constructor(options) {
|
|
4793
|
+
var _a2;
|
|
4794
|
+
this.llmProvider = options.llmProvider;
|
|
4795
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4796
|
+
this.documentSearch = options.documentSearch;
|
|
4797
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
4798
|
+
}
|
|
4799
|
+
/**
|
|
4800
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
4801
|
+
*/
|
|
4802
|
+
async run(question, history = []) {
|
|
4803
|
+
const generator = this.runStream(question, history);
|
|
4804
|
+
let finalReply = "";
|
|
4805
|
+
const sources = [];
|
|
4806
|
+
try {
|
|
4807
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4808
|
+
const chunk = temp.value;
|
|
4809
|
+
if (typeof chunk === "string") {
|
|
4810
|
+
finalReply += chunk;
|
|
4811
|
+
} else if (chunk && typeof chunk === "object") {
|
|
4812
|
+
if ("reply" in chunk && chunk.reply) {
|
|
4813
|
+
finalReply += chunk.reply;
|
|
4814
|
+
}
|
|
4815
|
+
if ("sources" in chunk && chunk.sources) {
|
|
4816
|
+
sources.push(...chunk.sources);
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
} catch (temp) {
|
|
4821
|
+
error = [temp];
|
|
4822
|
+
} finally {
|
|
4823
|
+
try {
|
|
4824
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4825
|
+
} finally {
|
|
4826
|
+
if (error)
|
|
4827
|
+
throw error[0];
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
return {
|
|
4831
|
+
reply: finalReply,
|
|
4832
|
+
sources
|
|
4833
|
+
};
|
|
4834
|
+
}
|
|
4835
|
+
/**
|
|
4836
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
4837
|
+
*/
|
|
4838
|
+
runStream(_0) {
|
|
4839
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
4840
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
4841
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
4842
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
4843
|
+
|
|
4844
|
+
Available Tools:
|
|
4845
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
4846
|
+
|
|
4847
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
4848
|
+
${mcpTools.map((mt) => {
|
|
4849
|
+
var _a2;
|
|
4850
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
4851
|
+
}).join("\n")}
|
|
4852
|
+
|
|
4853
|
+
Tool Calling Protocol:
|
|
4854
|
+
If you need to call a tool, write:
|
|
4855
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
4856
|
+
And then STOP generating immediately.
|
|
4857
|
+
|
|
4858
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
4859
|
+
`;
|
|
4860
|
+
const supervisorHistory = [
|
|
4861
|
+
{ role: "system", content: systemPrompt },
|
|
4862
|
+
...history,
|
|
4863
|
+
{ role: "user", content: question }
|
|
4864
|
+
];
|
|
4865
|
+
let iteration = 0;
|
|
4866
|
+
const allSources = [];
|
|
4867
|
+
while (iteration < this.maxIterations) {
|
|
4868
|
+
iteration++;
|
|
4869
|
+
const context = "";
|
|
4870
|
+
let fullModelResponse = "";
|
|
4871
|
+
let textBuffer = "";
|
|
4872
|
+
let inThinking = false;
|
|
4873
|
+
let toolCallDetected = null;
|
|
4874
|
+
if (!this.llmProvider.chatStream) {
|
|
4875
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
4876
|
+
fullModelResponse = reply;
|
|
4877
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
4878
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
4879
|
+
let thinkingText = "";
|
|
4880
|
+
let answerText = reply;
|
|
4881
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
4882
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
4883
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
4884
|
+
yield { type: "thinking", text: thinkingText };
|
|
4885
|
+
}
|
|
4886
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4887
|
+
if (toolMatch) {
|
|
4888
|
+
const toolName = toolMatch[1];
|
|
4889
|
+
const toolArgsStr = toolMatch[2];
|
|
4890
|
+
try {
|
|
4891
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4892
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4893
|
+
} catch (e) {
|
|
4894
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4895
|
+
}
|
|
4896
|
+
} else {
|
|
4897
|
+
yield answerText;
|
|
4898
|
+
}
|
|
4899
|
+
} else {
|
|
4900
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
4901
|
+
try {
|
|
4902
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
4903
|
+
const chunk = temp.value;
|
|
4904
|
+
fullModelResponse += chunk;
|
|
4905
|
+
textBuffer += chunk;
|
|
4906
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
4907
|
+
inThinking = true;
|
|
4908
|
+
const idx = textBuffer.indexOf("<think>");
|
|
4909
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
4910
|
+
}
|
|
4911
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
4912
|
+
inThinking = false;
|
|
4913
|
+
const idx = textBuffer.indexOf("</think>");
|
|
4914
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
4915
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
4916
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
4917
|
+
}
|
|
4918
|
+
if (inThinking && textBuffer.length > 0) {
|
|
4919
|
+
yield { type: "thinking", text: textBuffer };
|
|
4920
|
+
textBuffer = "";
|
|
4921
|
+
}
|
|
4922
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
4923
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
4924
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
4925
|
+
if (precedingText.trim()) {
|
|
4926
|
+
yield precedingText;
|
|
4927
|
+
}
|
|
4928
|
+
textBuffer = textBuffer.slice(idx);
|
|
4929
|
+
}
|
|
4930
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
4931
|
+
yield textBuffer;
|
|
4932
|
+
textBuffer = "";
|
|
4933
|
+
}
|
|
4934
|
+
}
|
|
4935
|
+
} catch (temp) {
|
|
4936
|
+
error = [temp];
|
|
4937
|
+
} finally {
|
|
4938
|
+
try {
|
|
4939
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
4940
|
+
} finally {
|
|
4941
|
+
if (error)
|
|
4942
|
+
throw error[0];
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
if (textBuffer.trim()) {
|
|
4946
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4947
|
+
if (toolMatch) {
|
|
4948
|
+
const toolName = toolMatch[1];
|
|
4949
|
+
const toolArgsStr = toolMatch[2];
|
|
4950
|
+
try {
|
|
4951
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4952
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4953
|
+
} catch (e) {
|
|
4954
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4955
|
+
}
|
|
4956
|
+
} else {
|
|
4957
|
+
yield textBuffer;
|
|
4958
|
+
}
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
4962
|
+
if (toolCallDetected) {
|
|
4963
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
4964
|
+
yield {
|
|
4965
|
+
type: "thinking",
|
|
4966
|
+
text: `
|
|
4967
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
4968
|
+
`
|
|
4969
|
+
};
|
|
4970
|
+
let toolResultText = "";
|
|
4971
|
+
try {
|
|
4972
|
+
if (toolName === "document_search") {
|
|
4973
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
4974
|
+
toolResultText = `document_search returned:
|
|
4975
|
+
${searchRes.reply}
|
|
4976
|
+
|
|
4977
|
+
Sources count: ${searchRes.sources.length}`;
|
|
4978
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
4979
|
+
allSources.push(...searchRes.sources);
|
|
4980
|
+
yield { reply: "", sources: searchRes.sources };
|
|
4981
|
+
}
|
|
4982
|
+
} else {
|
|
4983
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
4984
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
4985
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
4986
|
+
}
|
|
4987
|
+
} catch (err) {
|
|
4988
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
4989
|
+
}
|
|
4990
|
+
supervisorHistory.push({
|
|
4991
|
+
role: "user",
|
|
4992
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
4993
|
+
${toolResultText}`
|
|
4994
|
+
});
|
|
4995
|
+
yield {
|
|
4996
|
+
type: "thinking",
|
|
4997
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
4998
|
+
`
|
|
4999
|
+
};
|
|
5000
|
+
} else {
|
|
5001
|
+
break;
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
});
|
|
5005
|
+
}
|
|
5006
|
+
};
|
|
5007
|
+
|
|
4198
5008
|
// src/core/BatchProcessor.ts
|
|
4199
5009
|
function isTransientError(error) {
|
|
4200
5010
|
if (!(error instanceof Error)) return false;
|
|
@@ -4515,7 +5325,7 @@ var QueryProcessor = class {
|
|
|
4515
5325
|
* @param validFields Optional list of known filterable fields to look for
|
|
4516
5326
|
*/
|
|
4517
5327
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4518
|
-
var
|
|
5328
|
+
var _a2, _b, _c, _d;
|
|
4519
5329
|
if (!question.trim()) return [];
|
|
4520
5330
|
const hints = /* @__PURE__ */ new Map();
|
|
4521
5331
|
const addHint = (value, field) => {
|
|
@@ -4595,7 +5405,7 @@ var QueryProcessor = class {
|
|
|
4595
5405
|
];
|
|
4596
5406
|
for (const p of universalPatterns) {
|
|
4597
5407
|
for (const match of question.matchAll(p.regex)) {
|
|
4598
|
-
const val = p.group ? (
|
|
5408
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4599
5409
|
if (!val) continue;
|
|
4600
5410
|
if (p.field) addHint(val, p.field);
|
|
4601
5411
|
else addHint(val);
|
|
@@ -4819,11 +5629,11 @@ var LLMRouter = class {
|
|
|
4819
5629
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4820
5630
|
*/
|
|
4821
5631
|
async initialize(prebuiltDefault) {
|
|
4822
|
-
var
|
|
5632
|
+
var _a2;
|
|
4823
5633
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4824
5634
|
this.models.set("default", defaultModel);
|
|
4825
5635
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4826
|
-
const providerFastDefault = (
|
|
5636
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4827
5637
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4828
5638
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4829
5639
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4842,8 +5652,8 @@ var LLMRouter = class {
|
|
|
4842
5652
|
* Falls back to 'default' if the requested role is not registered.
|
|
4843
5653
|
*/
|
|
4844
5654
|
get(role) {
|
|
4845
|
-
var
|
|
4846
|
-
const provider = (
|
|
5655
|
+
var _a2;
|
|
5656
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4847
5657
|
if (!provider) {
|
|
4848
5658
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4849
5659
|
}
|
|
@@ -4861,7 +5671,7 @@ var UITransformer = class _UITransformer {
|
|
|
4861
5671
|
* Prefer `analyzeAndDecide()` in production.
|
|
4862
5672
|
*/
|
|
4863
5673
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4864
|
-
var
|
|
5674
|
+
var _a2, _b, _c;
|
|
4865
5675
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4866
5676
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4867
5677
|
}
|
|
@@ -4881,7 +5691,7 @@ var UITransformer = class _UITransformer {
|
|
|
4881
5691
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4882
5692
|
}
|
|
4883
5693
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4884
|
-
return (
|
|
5694
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4885
5695
|
}
|
|
4886
5696
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4887
5697
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5206,11 +6016,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5206
6016
|
};
|
|
5207
6017
|
}
|
|
5208
6018
|
static transformToPieChart(data, profile, query = "") {
|
|
5209
|
-
var
|
|
6019
|
+
var _a2;
|
|
5210
6020
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5211
6021
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5212
|
-
var
|
|
5213
|
-
return String((
|
|
6022
|
+
var _a3;
|
|
6023
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5214
6024
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5215
6025
|
if (categories.length === 0) return null;
|
|
5216
6026
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5220,7 +6030,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5220
6030
|
});
|
|
5221
6031
|
return {
|
|
5222
6032
|
type: "pie_chart",
|
|
5223
|
-
title: `Distribution by ${(
|
|
6033
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5224
6034
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5225
6035
|
data: pieData
|
|
5226
6036
|
};
|
|
@@ -5230,8 +6040,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5230
6040
|
const valueField = profile.numericFields[0];
|
|
5231
6041
|
const buckets = /* @__PURE__ */ new Map();
|
|
5232
6042
|
profile.records.forEach((record) => {
|
|
5233
|
-
var
|
|
5234
|
-
const timestamp = String((
|
|
6043
|
+
var _a2, _b, _c;
|
|
6044
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5235
6045
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5236
6046
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5237
6047
|
});
|
|
@@ -5244,23 +6054,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5244
6054
|
};
|
|
5245
6055
|
}
|
|
5246
6056
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5247
|
-
var
|
|
6057
|
+
var _a2;
|
|
5248
6058
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5249
6059
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5250
6060
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5251
6061
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5252
6062
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5253
|
-
var
|
|
6063
|
+
var _a3, _b, _c, _d, _e;
|
|
5254
6064
|
const meta = item.metadata || {};
|
|
5255
6065
|
const label = String(
|
|
5256
|
-
(_c = (_b = (
|
|
6066
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5257
6067
|
);
|
|
5258
6068
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5259
6069
|
return { category: label, value: Number(value) };
|
|
5260
6070
|
});
|
|
5261
6071
|
return {
|
|
5262
6072
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5263
|
-
title: dimension ? `${(
|
|
6073
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5264
6074
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5265
6075
|
data: fallbackData
|
|
5266
6076
|
};
|
|
@@ -5295,11 +6105,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5295
6105
|
if (fields.length < 2) return null;
|
|
5296
6106
|
const [xField, yField] = fields;
|
|
5297
6107
|
const points = profile.records.map((record) => {
|
|
5298
|
-
var
|
|
6108
|
+
var _a2;
|
|
5299
6109
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5300
6110
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5301
6111
|
if (x === null || y === null) return null;
|
|
5302
|
-
return { x, y, label: String((
|
|
6112
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5303
6113
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5304
6114
|
if (points.length === 0) return null;
|
|
5305
6115
|
return {
|
|
@@ -5329,9 +6139,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5329
6139
|
static transformToRadarChart(data) {
|
|
5330
6140
|
const attributeMap = {};
|
|
5331
6141
|
data.forEach((item) => {
|
|
5332
|
-
var
|
|
6142
|
+
var _a2, _b, _c;
|
|
5333
6143
|
const meta = item.metadata || {};
|
|
5334
|
-
const seriesName = String((_c = (_b = (
|
|
6144
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5335
6145
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5336
6146
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5337
6147
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5413,22 +6223,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5413
6223
|
return null;
|
|
5414
6224
|
}
|
|
5415
6225
|
static normalizeTransformation(payload) {
|
|
5416
|
-
var
|
|
6226
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5417
6227
|
if (!payload || typeof payload !== "object") return null;
|
|
5418
6228
|
const p = payload;
|
|
5419
6229
|
const type = this.normalizeVisualizationType(
|
|
5420
|
-
String((_c = (_b = (
|
|
6230
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5421
6231
|
);
|
|
5422
6232
|
if (!type) return null;
|
|
5423
6233
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5424
6234
|
const description = p.description ? String(p.description) : void 0;
|
|
5425
|
-
const rawData = (_j = (_i = (_h = (
|
|
6235
|
+
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;
|
|
5426
6236
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5427
6237
|
const transformation = { type, title, description, data };
|
|
5428
6238
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5429
6239
|
}
|
|
5430
6240
|
static normalizeVisualizationType(type) {
|
|
5431
|
-
var
|
|
6241
|
+
var _a2;
|
|
5432
6242
|
const mapping = {
|
|
5433
6243
|
pie: "pie_chart",
|
|
5434
6244
|
pie_chart: "pie_chart",
|
|
@@ -5456,7 +6266,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5456
6266
|
product_carousel: "product_carousel",
|
|
5457
6267
|
carousel: "carousel"
|
|
5458
6268
|
};
|
|
5459
|
-
return (
|
|
6269
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5460
6270
|
}
|
|
5461
6271
|
static validateTransformation(t) {
|
|
5462
6272
|
const { type, data } = t;
|
|
@@ -5658,16 +6468,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5658
6468
|
return null;
|
|
5659
6469
|
}
|
|
5660
6470
|
static selectDimensionField(profile, query) {
|
|
5661
|
-
var
|
|
6471
|
+
var _a2, _b;
|
|
5662
6472
|
const productCategory = profile.categoricalFields.find(
|
|
5663
6473
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5664
6474
|
);
|
|
5665
6475
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5666
|
-
return (_b = (
|
|
6476
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5667
6477
|
}
|
|
5668
6478
|
static selectNumericField(profile, query) {
|
|
5669
|
-
var
|
|
5670
|
-
return (
|
|
6479
|
+
var _a2;
|
|
6480
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5671
6481
|
}
|
|
5672
6482
|
static rankFieldsByQuery(fields, query) {
|
|
5673
6483
|
const q = query.toLowerCase();
|
|
@@ -5696,8 +6506,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5696
6506
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5697
6507
|
const result = {};
|
|
5698
6508
|
profile.records.forEach((record) => {
|
|
5699
|
-
var
|
|
5700
|
-
const category = String((
|
|
6509
|
+
var _a2, _b, _c;
|
|
6510
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5701
6511
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5702
6512
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5703
6513
|
});
|
|
@@ -5776,8 +6586,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5776
6586
|
static aggregateByCategory(data, categories) {
|
|
5777
6587
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5778
6588
|
data.forEach((item) => {
|
|
5779
|
-
var
|
|
5780
|
-
const cat = (
|
|
6589
|
+
var _a2;
|
|
6590
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5781
6591
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5782
6592
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5783
6593
|
});
|
|
@@ -5785,17 +6595,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5785
6595
|
}
|
|
5786
6596
|
static extractTimeSeriesData(data) {
|
|
5787
6597
|
return data.map((item) => {
|
|
5788
|
-
var
|
|
6598
|
+
var _a2, _b, _c, _d, _e;
|
|
5789
6599
|
const meta = item.metadata || {};
|
|
5790
6600
|
return {
|
|
5791
|
-
timestamp: (_b = (
|
|
6601
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5792
6602
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5793
6603
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5794
6604
|
};
|
|
5795
6605
|
});
|
|
5796
6606
|
}
|
|
5797
6607
|
static extractNumericValue(meta) {
|
|
5798
|
-
var
|
|
6608
|
+
var _a2;
|
|
5799
6609
|
const preferredKeys = [
|
|
5800
6610
|
"value",
|
|
5801
6611
|
"count",
|
|
@@ -5810,7 +6620,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5810
6620
|
"price"
|
|
5811
6621
|
];
|
|
5812
6622
|
for (const key of preferredKeys) {
|
|
5813
|
-
const raw = (
|
|
6623
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5814
6624
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5815
6625
|
if (Number.isFinite(value)) return value;
|
|
5816
6626
|
}
|
|
@@ -5956,8 +6766,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5956
6766
|
let inStock = 0;
|
|
5957
6767
|
let outOfStock = 0;
|
|
5958
6768
|
data.forEach((d) => {
|
|
5959
|
-
var
|
|
5960
|
-
const cat = (
|
|
6769
|
+
var _a2, _b;
|
|
6770
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
5961
6771
|
if (cat === category) {
|
|
5962
6772
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
5963
6773
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -6001,9 +6811,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
6001
6811
|
}
|
|
6002
6812
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
6003
6813
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
6004
|
-
var
|
|
6814
|
+
var _a2;
|
|
6005
6815
|
if (!meta) return void 0;
|
|
6006
|
-
const mapping = (
|
|
6816
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
6007
6817
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
6008
6818
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
6009
6819
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -6012,13 +6822,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6012
6822
|
return resolveMetadataValue(meta, uiKey);
|
|
6013
6823
|
}
|
|
6014
6824
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6015
|
-
var
|
|
6825
|
+
var _a2;
|
|
6016
6826
|
const meta = item.metadata || {};
|
|
6017
6827
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6018
6828
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6019
6829
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6020
6830
|
const description = this.cleanProductDescription(
|
|
6021
|
-
(
|
|
6831
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6022
6832
|
);
|
|
6023
6833
|
if (name || this.isProductData(item)) {
|
|
6024
6834
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6126,10 +6936,10 @@ RULES:
|
|
|
6126
6936
|
}
|
|
6127
6937
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6128
6938
|
const items = sources.map((s, i) => {
|
|
6129
|
-
var
|
|
6939
|
+
var _a2, _b, _c, _d;
|
|
6130
6940
|
return {
|
|
6131
6941
|
index: i + 1,
|
|
6132
|
-
content: (_b = (
|
|
6942
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6133
6943
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6134
6944
|
score: (_d = s.score) != null ? _d : 0
|
|
6135
6945
|
};
|
|
@@ -6322,9 +7132,11 @@ var Pipeline = class {
|
|
|
6322
7132
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6323
7133
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6324
7134
|
this.initialised = false;
|
|
6325
|
-
|
|
7135
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7136
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7137
|
+
var _a2, _b, _c, _d, _e;
|
|
6326
7138
|
this.chunker = new DocumentChunker(
|
|
6327
|
-
(_b = (
|
|
7139
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6328
7140
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6329
7141
|
);
|
|
6330
7142
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6340,7 +7152,7 @@ var Pipeline = class {
|
|
|
6340
7152
|
return this.initialised ? this.llmProvider : void 0;
|
|
6341
7153
|
}
|
|
6342
7154
|
async initialize() {
|
|
6343
|
-
var
|
|
7155
|
+
var _a2, _b, _c;
|
|
6344
7156
|
if (this.initialised) return;
|
|
6345
7157
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6346
7158
|
|
|
@@ -6383,12 +7195,47 @@ var Pipeline = class {
|
|
|
6383
7195
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6384
7196
|
}
|
|
6385
7197
|
await this.vectorDB.initialize();
|
|
6386
|
-
if (((
|
|
7198
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7199
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7200
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7201
|
+
llmProvider: this.llmProvider,
|
|
7202
|
+
mcpRegistry: this.mcpRegistry,
|
|
7203
|
+
documentSearch: async (query) => {
|
|
7204
|
+
return this.runNormalQuery(query);
|
|
7205
|
+
}
|
|
7206
|
+
});
|
|
6387
7207
|
this.agent = new LangChainAgent(this, this.config);
|
|
6388
7208
|
await this.agent.initialize(this.llmProvider);
|
|
6389
7209
|
}
|
|
7210
|
+
if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
|
|
7211
|
+
await this.loadColdContext(this.config.projectId);
|
|
7212
|
+
}
|
|
6390
7213
|
this.initialised = true;
|
|
6391
7214
|
}
|
|
7215
|
+
async loadColdContext(ns) {
|
|
7216
|
+
var _a2, _b;
|
|
7217
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7218
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7219
|
+
try {
|
|
7220
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7221
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7222
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7223
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7224
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7225
|
+
if (coldMatches.length > 0) {
|
|
7226
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7227
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7228
|
+
this.coldContexts.set(ns, formatted);
|
|
7229
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7230
|
+
} else {
|
|
7231
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7232
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7233
|
+
}
|
|
7234
|
+
} catch (err) {
|
|
7235
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7236
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
6392
7239
|
/**
|
|
6393
7240
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6394
7241
|
*/
|
|
@@ -6420,12 +7267,12 @@ var Pipeline = class {
|
|
|
6420
7267
|
}
|
|
6421
7268
|
/** Step 1: Chunk the document content. */
|
|
6422
7269
|
async prepareChunks(doc) {
|
|
6423
|
-
var
|
|
7270
|
+
var _a2, _b;
|
|
6424
7271
|
if (this.llamaIngestor) {
|
|
6425
7272
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6426
7273
|
docId: doc.docId,
|
|
6427
7274
|
metadata: doc.metadata,
|
|
6428
|
-
chunkSize: (
|
|
7275
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6429
7276
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6430
7277
|
});
|
|
6431
7278
|
}
|
|
@@ -6447,7 +7294,7 @@ var Pipeline = class {
|
|
|
6447
7294
|
embedBatchOptions
|
|
6448
7295
|
);
|
|
6449
7296
|
if (vectors.length !== chunks.length) {
|
|
6450
|
-
throw new
|
|
7297
|
+
throw new EmbeddingFailedException(
|
|
6451
7298
|
`[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
|
|
6452
7299
|
);
|
|
6453
7300
|
}
|
|
@@ -6496,12 +7343,37 @@ var Pipeline = class {
|
|
|
6496
7343
|
extractionOptions
|
|
6497
7344
|
);
|
|
6498
7345
|
}
|
|
7346
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7347
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7348
|
+
let reply = "";
|
|
7349
|
+
let sources = [];
|
|
7350
|
+
try {
|
|
7351
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7352
|
+
const chunk = temp.value;
|
|
7353
|
+
if (typeof chunk === "string") {
|
|
7354
|
+
reply += chunk;
|
|
7355
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7356
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7357
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7358
|
+
}
|
|
7359
|
+
}
|
|
7360
|
+
} catch (temp) {
|
|
7361
|
+
error = [temp];
|
|
7362
|
+
} finally {
|
|
7363
|
+
try {
|
|
7364
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7365
|
+
} finally {
|
|
7366
|
+
if (error)
|
|
7367
|
+
throw error[0];
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
return { reply, sources };
|
|
7371
|
+
}
|
|
6499
7372
|
async ask(question, history = [], namespace) {
|
|
6500
|
-
var
|
|
7373
|
+
var _a2;
|
|
6501
7374
|
await this.initialize();
|
|
6502
|
-
if (((
|
|
6503
|
-
|
|
6504
|
-
return { reply: agentReply, sources: [] };
|
|
7375
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7376
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6505
7377
|
}
|
|
6506
7378
|
const stream = this.askStream(question, history, namespace);
|
|
6507
7379
|
let reply = "";
|
|
@@ -6525,13 +7397,54 @@ var Pipeline = class {
|
|
|
6525
7397
|
error = [temp];
|
|
6526
7398
|
} finally {
|
|
6527
7399
|
try {
|
|
6528
|
-
more && (temp = iter.return) && await temp.call(iter);
|
|
7400
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7401
|
+
} finally {
|
|
7402
|
+
if (error)
|
|
7403
|
+
throw error[0];
|
|
7404
|
+
}
|
|
7405
|
+
}
|
|
7406
|
+
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7407
|
+
}
|
|
7408
|
+
askStream(_0) {
|
|
7409
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7410
|
+
var _a2;
|
|
7411
|
+
yield new __await(this.initialize());
|
|
7412
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7413
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7414
|
+
try {
|
|
7415
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7416
|
+
const chunk = temp.value;
|
|
7417
|
+
yield chunk;
|
|
7418
|
+
}
|
|
7419
|
+
} catch (temp) {
|
|
7420
|
+
error = [temp];
|
|
7421
|
+
} finally {
|
|
7422
|
+
try {
|
|
7423
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7424
|
+
} finally {
|
|
7425
|
+
if (error)
|
|
7426
|
+
throw error[0];
|
|
7427
|
+
}
|
|
7428
|
+
}
|
|
7429
|
+
return;
|
|
7430
|
+
}
|
|
7431
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7432
|
+
try {
|
|
7433
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7434
|
+
const chunk = temp2.value;
|
|
7435
|
+
yield chunk;
|
|
7436
|
+
}
|
|
7437
|
+
} catch (temp2) {
|
|
7438
|
+
error2 = [temp2];
|
|
6529
7439
|
} finally {
|
|
6530
|
-
|
|
6531
|
-
|
|
7440
|
+
try {
|
|
7441
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7442
|
+
} finally {
|
|
7443
|
+
if (error2)
|
|
7444
|
+
throw error2[0];
|
|
7445
|
+
}
|
|
6532
7446
|
}
|
|
6533
|
-
}
|
|
6534
|
-
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
7447
|
+
});
|
|
6535
7448
|
}
|
|
6536
7449
|
/**
|
|
6537
7450
|
* High-performance streaming RAG flow.
|
|
@@ -6543,12 +7456,12 @@ var Pipeline = class {
|
|
|
6543
7456
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6544
7457
|
* - SchemaMapper.train runs while answer generation streams
|
|
6545
7458
|
*/
|
|
6546
|
-
|
|
7459
|
+
askStreamInternal(_0) {
|
|
6547
7460
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6548
|
-
var
|
|
7461
|
+
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;
|
|
6549
7462
|
yield new __await(this.initialize());
|
|
6550
7463
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6551
|
-
const topK = (_b = (
|
|
7464
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6552
7465
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6553
7466
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6554
7467
|
const requestStart = performance.now();
|
|
@@ -6561,7 +7474,7 @@ var Pipeline = class {
|
|
|
6561
7474
|
}
|
|
6562
7475
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6563
7476
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6564
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7477
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6565
7478
|
if (numericPredicates.length > 0) {
|
|
6566
7479
|
filter.__numericPredicates = numericPredicates;
|
|
6567
7480
|
}
|
|
@@ -6627,6 +7540,32 @@ ${graphContext}
|
|
|
6627
7540
|
VECTOR CONTEXT:
|
|
6628
7541
|
${context}`;
|
|
6629
7542
|
}
|
|
7543
|
+
if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
|
|
7544
|
+
if (!this.coldContexts.has(ns)) {
|
|
7545
|
+
yield new __await(this.loadColdContext(ns));
|
|
7546
|
+
}
|
|
7547
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7548
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7549
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7550
|
+
${coldContext}
|
|
7551
|
+
|
|
7552
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7553
|
+
${context}`;
|
|
7554
|
+
}
|
|
7555
|
+
}
|
|
7556
|
+
yield {
|
|
7557
|
+
reply: "",
|
|
7558
|
+
sources: sources.map((s) => {
|
|
7559
|
+
var _a3;
|
|
7560
|
+
return {
|
|
7561
|
+
id: s.id,
|
|
7562
|
+
score: s.score,
|
|
7563
|
+
content: s.content,
|
|
7564
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7565
|
+
namespace: ns
|
|
7566
|
+
};
|
|
7567
|
+
})
|
|
7568
|
+
};
|
|
6630
7569
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6631
7570
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6632
7571
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6654,10 +7593,10 @@ ${context}`;
|
|
|
6654
7593
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6655
7594
|
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.)";
|
|
6656
7595
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6657
|
-
const isNativeThinking = isClaude37 && (((
|
|
7596
|
+
const isNativeThinking = isClaude37 && (((_o = this.config.llm.options) == null ? void 0 : _o.thinking) === true || ((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === "enabled" || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) !== false);
|
|
6658
7597
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6659
7598
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6660
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7599
|
+
const isSimulatedThinking = !isNativeThinking && (((_r = this.config.llm.options) == null ? void 0 : _r.thinking) === true || ((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === "enabled" || isReasoningModel && ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) !== false);
|
|
6661
7600
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6662
7601
|
if (isSimulatedThinking) {
|
|
6663
7602
|
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.`)";
|
|
@@ -6665,7 +7604,7 @@ ${context}`;
|
|
|
6665
7604
|
const hardenedHistory = [...history];
|
|
6666
7605
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6667
7606
|
const messages = [...hardenedHistory, userQuestion];
|
|
6668
|
-
const systemPrompt = (
|
|
7607
|
+
const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
|
|
6669
7608
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6670
7609
|
let fullReply = "";
|
|
6671
7610
|
let thinkingText = "";
|
|
@@ -6776,7 +7715,7 @@ ${context}`;
|
|
|
6776
7715
|
}
|
|
6777
7716
|
yield fullReply;
|
|
6778
7717
|
}
|
|
6779
|
-
const runHallucination = ((
|
|
7718
|
+
const runHallucination = ((_v = this.config.llm.options) == null ? void 0 : _v.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) !== false;
|
|
6780
7719
|
if (runHallucination) {
|
|
6781
7720
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6782
7721
|
}
|
|
@@ -6785,7 +7724,7 @@ ${context}`;
|
|
|
6785
7724
|
const latency = {
|
|
6786
7725
|
embedMs: Math.round(embedMs),
|
|
6787
7726
|
retrieveMs: Math.round(retrieveMs),
|
|
6788
|
-
rerankMs: ((
|
|
7727
|
+
rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6789
7728
|
generateMs: Math.round(generateMs),
|
|
6790
7729
|
totalMs: Math.round(totalMs)
|
|
6791
7730
|
};
|
|
@@ -6798,33 +7737,63 @@ ${context}`;
|
|
|
6798
7737
|
totalTokens: promptTokens + completionTokens,
|
|
6799
7738
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6800
7739
|
};
|
|
7740
|
+
const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
|
|
6801
7741
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6802
7742
|
uiTransformationPromise,
|
|
6803
|
-
hallucinationScoringPromise
|
|
7743
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6804
7744
|
]));
|
|
6805
|
-
const
|
|
7745
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6806
7746
|
requestId,
|
|
6807
7747
|
query: question,
|
|
6808
7748
|
rewrittenQuery,
|
|
6809
7749
|
systemPrompt,
|
|
6810
7750
|
userPrompt: question + finalRestrictionSuffix,
|
|
6811
7751
|
chunks: sources.map((s) => {
|
|
6812
|
-
var
|
|
7752
|
+
var _a3;
|
|
6813
7753
|
return {
|
|
6814
7754
|
id: s.id,
|
|
6815
7755
|
score: s.score,
|
|
6816
7756
|
content: s.content,
|
|
6817
|
-
metadata: (
|
|
7757
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6818
7758
|
namespace: ns
|
|
6819
7759
|
};
|
|
6820
7760
|
}),
|
|
6821
7761
|
latency,
|
|
6822
7762
|
tokens,
|
|
6823
7763
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6824
|
-
},
|
|
6825
|
-
hallucinationScore:
|
|
6826
|
-
hallucinationReason:
|
|
7764
|
+
}, hScore ? {
|
|
7765
|
+
hallucinationScore: hScore.score,
|
|
7766
|
+
hallucinationReason: hScore.reason
|
|
6827
7767
|
} : {});
|
|
7768
|
+
const trace = buildTrace(hallucinationResult);
|
|
7769
|
+
if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
|
|
7770
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7771
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7772
|
+
(async () => {
|
|
7773
|
+
try {
|
|
7774
|
+
let finalTrace = trace;
|
|
7775
|
+
if (!awaitHallucination && runHallucination) {
|
|
7776
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7777
|
+
if (backgroundScoreResult) {
|
|
7778
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7779
|
+
}
|
|
7780
|
+
}
|
|
7781
|
+
await fetch(absoluteUrl, {
|
|
7782
|
+
method: "POST",
|
|
7783
|
+
headers: {
|
|
7784
|
+
"Content-Type": "application/json"
|
|
7785
|
+
},
|
|
7786
|
+
body: JSON.stringify({
|
|
7787
|
+
trace: finalTrace,
|
|
7788
|
+
licenseKey: this.config.licenseKey,
|
|
7789
|
+
projectId: ns
|
|
7790
|
+
})
|
|
7791
|
+
});
|
|
7792
|
+
} catch (err) {
|
|
7793
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
7794
|
+
}
|
|
7795
|
+
})();
|
|
7796
|
+
}
|
|
6828
7797
|
yield {
|
|
6829
7798
|
reply: "",
|
|
6830
7799
|
sources,
|
|
@@ -6844,7 +7813,7 @@ ${context}`;
|
|
|
6844
7813
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6845
7814
|
*/
|
|
6846
7815
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6847
|
-
var
|
|
7816
|
+
var _a2;
|
|
6848
7817
|
if (!sources || sources.length === 0) {
|
|
6849
7818
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6850
7819
|
}
|
|
@@ -6858,7 +7827,7 @@ ${context}`;
|
|
|
6858
7827
|
);
|
|
6859
7828
|
}
|
|
6860
7829
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6861
|
-
const disableLlmUiTransform = ((
|
|
7830
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6862
7831
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6863
7832
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6864
7833
|
}
|
|
@@ -6876,9 +7845,9 @@ ${context}`;
|
|
|
6876
7845
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6877
7846
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6878
7847
|
})).sort((a, b) => {
|
|
6879
|
-
var
|
|
7848
|
+
var _a2, _b;
|
|
6880
7849
|
const primary = predicates[0];
|
|
6881
|
-
const aValue = (
|
|
7850
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6882
7851
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6883
7852
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6884
7853
|
});
|
|
@@ -6950,8 +7919,8 @@ ${context}`;
|
|
|
6950
7919
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6951
7920
|
}
|
|
6952
7921
|
async retrieve(query, options) {
|
|
6953
|
-
var
|
|
6954
|
-
const ns = (
|
|
7922
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
7923
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
6955
7924
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6956
7925
|
const cacheKey = `${ns}::${query}`;
|
|
6957
7926
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -6983,7 +7952,7 @@ ${context}`;
|
|
|
6983
7952
|
) : [];
|
|
6984
7953
|
const resolvedSources = [];
|
|
6985
7954
|
for (const source of sources) {
|
|
6986
|
-
const parentId = (
|
|
7955
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
6987
7956
|
if (parentId) {
|
|
6988
7957
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6989
7958
|
resolvedSources.push(source);
|
|
@@ -7161,12 +8130,142 @@ var ProviderHealthCheck = class {
|
|
|
7161
8130
|
}
|
|
7162
8131
|
};
|
|
7163
8132
|
|
|
8133
|
+
// src/core/LicenseVerifier.ts
|
|
8134
|
+
var crypto2 = __toESM(require("crypto"));
|
|
8135
|
+
var LicenseVerifier = class {
|
|
8136
|
+
/**
|
|
8137
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
8138
|
+
*
|
|
8139
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
8140
|
+
* @param currentProjectId - Project namespace ID.
|
|
8141
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
8142
|
+
*/
|
|
8143
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
8144
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
8145
|
+
if (!licenseKey) {
|
|
8146
|
+
if (isProduction) {
|
|
8147
|
+
throw new ConfigurationException(
|
|
8148
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
8149
|
+
);
|
|
8150
|
+
}
|
|
8151
|
+
console.warn(
|
|
8152
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
8153
|
+
);
|
|
8154
|
+
return {
|
|
8155
|
+
projectId: currentProjectId,
|
|
8156
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
8157
|
+
// Valid for 24h
|
|
8158
|
+
tier: "hobby"
|
|
8159
|
+
};
|
|
8160
|
+
}
|
|
8161
|
+
try {
|
|
8162
|
+
const parts = licenseKey.split(".");
|
|
8163
|
+
if (parts.length !== 3) {
|
|
8164
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
8165
|
+
}
|
|
8166
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
8167
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
8168
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
8169
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
8170
|
+
const data = Buffer.from(dataToVerify);
|
|
8171
|
+
const isValid = crypto2.verify(
|
|
8172
|
+
"sha256",
|
|
8173
|
+
data,
|
|
8174
|
+
publicKey,
|
|
8175
|
+
signature
|
|
8176
|
+
);
|
|
8177
|
+
if (!isValid) {
|
|
8178
|
+
throw new Error("Signature verification failed.");
|
|
8179
|
+
}
|
|
8180
|
+
const payload = JSON.parse(
|
|
8181
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8182
|
+
);
|
|
8183
|
+
if (!payload.projectId) {
|
|
8184
|
+
throw new Error('License payload is missing "projectId".');
|
|
8185
|
+
}
|
|
8186
|
+
if (payload.projectId !== currentProjectId) {
|
|
8187
|
+
throw new Error(
|
|
8188
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
8189
|
+
);
|
|
8190
|
+
}
|
|
8191
|
+
if (!payload.expiresAt) {
|
|
8192
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
8193
|
+
}
|
|
8194
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
8195
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
8196
|
+
throw new Error(
|
|
8197
|
+
`License key has expired. Expiration: ${new Date(
|
|
8198
|
+
payload.expiresAt * 1e3
|
|
8199
|
+
).toDateString()}`
|
|
8200
|
+
);
|
|
8201
|
+
}
|
|
8202
|
+
if (isProduction && provider) {
|
|
8203
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8204
|
+
const normalizedProvider = provider.toLowerCase();
|
|
8205
|
+
if (tier === "hobby") {
|
|
8206
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
8207
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
8208
|
+
throw new Error(
|
|
8209
|
+
`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.`
|
|
8210
|
+
);
|
|
8211
|
+
}
|
|
8212
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
8213
|
+
const allowedPro = [
|
|
8214
|
+
"postgresql",
|
|
8215
|
+
"pgvector",
|
|
8216
|
+
"supabase",
|
|
8217
|
+
"pinecone",
|
|
8218
|
+
"qdrant",
|
|
8219
|
+
"mongodb",
|
|
8220
|
+
"milvus",
|
|
8221
|
+
"chroma",
|
|
8222
|
+
"chromadb"
|
|
8223
|
+
];
|
|
8224
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
8225
|
+
throw new Error(
|
|
8226
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
8227
|
+
);
|
|
8228
|
+
}
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8231
|
+
return payload;
|
|
8232
|
+
} catch (err) {
|
|
8233
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8234
|
+
throw new ConfigurationException(
|
|
8235
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
8236
|
+
);
|
|
8237
|
+
}
|
|
8238
|
+
}
|
|
8239
|
+
};
|
|
8240
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
8241
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
8242
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
8243
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
8244
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
8245
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
8246
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
8247
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
8248
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
8249
|
+
MwIDAQAB
|
|
8250
|
+
-----END PUBLIC KEY-----`;
|
|
8251
|
+
|
|
7164
8252
|
// src/core/VectorPlugin.ts
|
|
7165
8253
|
var VectorPlugin = class {
|
|
7166
8254
|
constructor(hostConfig) {
|
|
7167
|
-
|
|
7168
|
-
this.
|
|
7169
|
-
this.
|
|
8255
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8256
|
+
this.config = resolvedConfig;
|
|
8257
|
+
this.validationPromise = (async () => {
|
|
8258
|
+
var _a2;
|
|
8259
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8260
|
+
LicenseVerifier.verify(
|
|
8261
|
+
resolvedConfig.licenseKey,
|
|
8262
|
+
resolvedConfig.projectId,
|
|
8263
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8264
|
+
);
|
|
8265
|
+
})();
|
|
8266
|
+
this.validationPromise.catch(() => {
|
|
8267
|
+
});
|
|
8268
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7170
8269
|
}
|
|
7171
8270
|
/**
|
|
7172
8271
|
* Get the current resolved configuration.
|
|
@@ -7199,31 +8298,93 @@ var VectorPlugin = class {
|
|
|
7199
8298
|
* Run a chat query.
|
|
7200
8299
|
*/
|
|
7201
8300
|
async chat(message, history = [], namespace) {
|
|
7202
|
-
|
|
7203
|
-
|
|
8301
|
+
try {
|
|
8302
|
+
await this.validationPromise;
|
|
8303
|
+
} catch (err) {
|
|
8304
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8305
|
+
}
|
|
8306
|
+
try {
|
|
8307
|
+
return await this.pipeline.ask(message, history, namespace);
|
|
8308
|
+
} catch (err) {
|
|
8309
|
+
const msg = String(err);
|
|
8310
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8311
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8312
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8313
|
+
}
|
|
8314
|
+
throw wrapError(err, defaultCode);
|
|
8315
|
+
}
|
|
7204
8316
|
}
|
|
7205
8317
|
/**
|
|
7206
8318
|
* Run a streaming chat query.
|
|
7207
8319
|
*/
|
|
7208
8320
|
chatStream(_0) {
|
|
7209
8321
|
return __asyncGenerator(this, arguments, function* (message, history = [], namespace) {
|
|
7210
|
-
|
|
7211
|
-
|
|
8322
|
+
try {
|
|
8323
|
+
yield new __await(this.validationPromise);
|
|
8324
|
+
} catch (err) {
|
|
8325
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8326
|
+
}
|
|
8327
|
+
try {
|
|
8328
|
+
const stream = this.pipeline.askStream(message, history, namespace);
|
|
8329
|
+
try {
|
|
8330
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
8331
|
+
const chunk = temp.value;
|
|
8332
|
+
yield chunk;
|
|
8333
|
+
}
|
|
8334
|
+
} catch (temp) {
|
|
8335
|
+
error = [temp];
|
|
8336
|
+
} finally {
|
|
8337
|
+
try {
|
|
8338
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
8339
|
+
} finally {
|
|
8340
|
+
if (error)
|
|
8341
|
+
throw error[0];
|
|
8342
|
+
}
|
|
8343
|
+
}
|
|
8344
|
+
} catch (err) {
|
|
8345
|
+
const msg = String(err);
|
|
8346
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8347
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8348
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8349
|
+
}
|
|
8350
|
+
throw wrapError(err, defaultCode);
|
|
8351
|
+
}
|
|
7212
8352
|
});
|
|
7213
8353
|
}
|
|
7214
8354
|
/**
|
|
7215
8355
|
* Ingest documents into the vector database.
|
|
7216
8356
|
*/
|
|
7217
8357
|
async ingest(documents, namespace) {
|
|
7218
|
-
|
|
7219
|
-
|
|
8358
|
+
try {
|
|
8359
|
+
await this.validationPromise;
|
|
8360
|
+
} catch (err) {
|
|
8361
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8362
|
+
}
|
|
8363
|
+
try {
|
|
8364
|
+
return await this.pipeline.ingest(documents, namespace);
|
|
8365
|
+
} catch (err) {
|
|
8366
|
+
const msg = String(err);
|
|
8367
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8368
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8369
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8370
|
+
}
|
|
8371
|
+
throw wrapError(err, defaultCode);
|
|
8372
|
+
}
|
|
7220
8373
|
}
|
|
7221
8374
|
/**
|
|
7222
8375
|
* Get auto-suggestions based on a query prefix.
|
|
7223
8376
|
*/
|
|
7224
8377
|
async getSuggestions(query, namespace) {
|
|
7225
|
-
|
|
7226
|
-
|
|
8378
|
+
try {
|
|
8379
|
+
await this.validationPromise;
|
|
8380
|
+
} catch (err) {
|
|
8381
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8382
|
+
}
|
|
8383
|
+
try {
|
|
8384
|
+
return await this.pipeline.getSuggestions(query, namespace);
|
|
8385
|
+
} catch (err) {
|
|
8386
|
+
throw wrapError(err, "RETRIEVAL_FAILED");
|
|
8387
|
+
}
|
|
7227
8388
|
}
|
|
7228
8389
|
};
|
|
7229
8390
|
|
|
@@ -7233,8 +8394,8 @@ var DocumentParser = class {
|
|
|
7233
8394
|
* Extract text from a File or Buffer based on its type.
|
|
7234
8395
|
*/
|
|
7235
8396
|
static async parse(file, fileName, mimeType) {
|
|
7236
|
-
var
|
|
7237
|
-
const extension = (
|
|
8397
|
+
var _a2;
|
|
8398
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7238
8399
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7239
8400
|
return this.readAsText(file);
|
|
7240
8401
|
}
|
|
@@ -7286,7 +8447,496 @@ var DocumentParser = class {
|
|
|
7286
8447
|
}
|
|
7287
8448
|
};
|
|
7288
8449
|
|
|
8450
|
+
// src/core/DatabaseStorage.ts
|
|
8451
|
+
var fs = __toESM(require("fs"));
|
|
8452
|
+
var path = __toESM(require("path"));
|
|
8453
|
+
var DatabaseStorage = class {
|
|
8454
|
+
constructor(config) {
|
|
8455
|
+
// Dynamic PG Pool
|
|
8456
|
+
this.pgPool = null;
|
|
8457
|
+
// Dynamic MongoDB Client
|
|
8458
|
+
this.mongoClient = null;
|
|
8459
|
+
this.mongoDbName = "";
|
|
8460
|
+
// Filesystem fallback configuration
|
|
8461
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8462
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8463
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8464
|
+
var _a2, _b, _c, _d, _e;
|
|
8465
|
+
this.config = config;
|
|
8466
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8467
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8468
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8469
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8470
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8471
|
+
}
|
|
8472
|
+
/**
|
|
8473
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8474
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8475
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8476
|
+
*/
|
|
8477
|
+
checkPremiumSubscription() {
|
|
8478
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8479
|
+
return;
|
|
8480
|
+
}
|
|
8481
|
+
if (!this.config.licenseKey) {
|
|
8482
|
+
throw new Error(
|
|
8483
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8484
|
+
);
|
|
8485
|
+
}
|
|
8486
|
+
try {
|
|
8487
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8488
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8489
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8490
|
+
throw new Error(
|
|
8491
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8492
|
+
);
|
|
8493
|
+
}
|
|
8494
|
+
} catch (err) {
|
|
8495
|
+
throw new Error(
|
|
8496
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8497
|
+
);
|
|
8498
|
+
}
|
|
8499
|
+
}
|
|
8500
|
+
checkHistoryEnabled() {
|
|
8501
|
+
var _a2, _b;
|
|
8502
|
+
this.checkPremiumSubscription();
|
|
8503
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8504
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8505
|
+
}
|
|
8506
|
+
}
|
|
8507
|
+
checkFeedbackEnabled() {
|
|
8508
|
+
var _a2, _b;
|
|
8509
|
+
this.checkPremiumSubscription();
|
|
8510
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8511
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8512
|
+
}
|
|
8513
|
+
}
|
|
8514
|
+
async getPGPool() {
|
|
8515
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8516
|
+
const _g2 = global;
|
|
8517
|
+
if (_g2[globalKey]) {
|
|
8518
|
+
this.pgPool = _g2[globalKey];
|
|
8519
|
+
return this.pgPool;
|
|
8520
|
+
}
|
|
8521
|
+
const opts = this.config.vectorDb.options;
|
|
8522
|
+
if (!opts.connectionString) {
|
|
8523
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8524
|
+
}
|
|
8525
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8526
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8527
|
+
_g2[globalKey] = this.pgPool;
|
|
8528
|
+
const client = await this.pgPool.connect();
|
|
8529
|
+
try {
|
|
8530
|
+
await client.query(`
|
|
8531
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8532
|
+
id TEXT PRIMARY KEY,
|
|
8533
|
+
session_id TEXT NOT NULL,
|
|
8534
|
+
role TEXT NOT NULL,
|
|
8535
|
+
content TEXT NOT NULL,
|
|
8536
|
+
sources JSONB,
|
|
8537
|
+
ui_transformation JSONB,
|
|
8538
|
+
trace JSONB,
|
|
8539
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8540
|
+
)
|
|
8541
|
+
`);
|
|
8542
|
+
await client.query(`
|
|
8543
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8544
|
+
id TEXT PRIMARY KEY,
|
|
8545
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8546
|
+
session_id TEXT NOT NULL,
|
|
8547
|
+
rating TEXT NOT NULL,
|
|
8548
|
+
comment TEXT,
|
|
8549
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8550
|
+
)
|
|
8551
|
+
`);
|
|
8552
|
+
} finally {
|
|
8553
|
+
client.release();
|
|
8554
|
+
}
|
|
8555
|
+
return this.pgPool;
|
|
8556
|
+
}
|
|
8557
|
+
async getMongoClient() {
|
|
8558
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8559
|
+
const _g2 = global;
|
|
8560
|
+
if (_g2[globalKey]) {
|
|
8561
|
+
this.mongoClient = _g2[globalKey];
|
|
8562
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8563
|
+
return this.mongoClient;
|
|
8564
|
+
}
|
|
8565
|
+
const opts = this.config.vectorDb.options;
|
|
8566
|
+
if (!opts.uri || !opts.database) {
|
|
8567
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8568
|
+
}
|
|
8569
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8570
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8571
|
+
await this.mongoClient.connect();
|
|
8572
|
+
_g2[globalKey] = this.mongoClient;
|
|
8573
|
+
this.mongoDbName = opts.database;
|
|
8574
|
+
return this.mongoClient;
|
|
8575
|
+
}
|
|
8576
|
+
getMongoDb() {
|
|
8577
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8578
|
+
}
|
|
8579
|
+
// Helper for FS fallback reads
|
|
8580
|
+
readLocalFile(filePath) {
|
|
8581
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8582
|
+
try {
|
|
8583
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8584
|
+
return JSON.parse(raw) || [];
|
|
8585
|
+
} catch (e) {
|
|
8586
|
+
return [];
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
// Helper for FS fallback writes
|
|
8590
|
+
writeLocalFile(filePath, data) {
|
|
8591
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8592
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8593
|
+
}
|
|
8594
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8595
|
+
}
|
|
8596
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8597
|
+
async saveMessage(sessionId, message) {
|
|
8598
|
+
this.checkHistoryEnabled();
|
|
8599
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8600
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8601
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8602
|
+
const pool = await this.getPGPool();
|
|
8603
|
+
await pool.query(
|
|
8604
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8605
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8606
|
+
ON CONFLICT (id) DO UPDATE
|
|
8607
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8608
|
+
[
|
|
8609
|
+
msgId,
|
|
8610
|
+
sessionId,
|
|
8611
|
+
message.role,
|
|
8612
|
+
message.content,
|
|
8613
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
8614
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
8615
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
8616
|
+
createdAt
|
|
8617
|
+
]
|
|
8618
|
+
);
|
|
8619
|
+
} else if (this.provider === "mongodb") {
|
|
8620
|
+
await this.getMongoClient();
|
|
8621
|
+
const db = this.getMongoDb();
|
|
8622
|
+
const col = db.collection(this.historyTableName);
|
|
8623
|
+
await col.updateOne(
|
|
8624
|
+
{ id: msgId },
|
|
8625
|
+
{
|
|
8626
|
+
$set: {
|
|
8627
|
+
id: msgId,
|
|
8628
|
+
session_id: sessionId,
|
|
8629
|
+
role: message.role,
|
|
8630
|
+
content: message.content,
|
|
8631
|
+
sources: message.sources || null,
|
|
8632
|
+
ui_transformation: message.uiTransformation || null,
|
|
8633
|
+
trace: message.trace || null,
|
|
8634
|
+
created_at: createdAt
|
|
8635
|
+
}
|
|
8636
|
+
},
|
|
8637
|
+
{ upsert: true }
|
|
8638
|
+
);
|
|
8639
|
+
} else {
|
|
8640
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8641
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
8642
|
+
const item = {
|
|
8643
|
+
id: msgId,
|
|
8644
|
+
session_id: sessionId,
|
|
8645
|
+
role: message.role,
|
|
8646
|
+
content: message.content,
|
|
8647
|
+
sources: message.sources || null,
|
|
8648
|
+
ui_transformation: message.uiTransformation || null,
|
|
8649
|
+
trace: message.trace || null,
|
|
8650
|
+
created_at: createdAt
|
|
8651
|
+
};
|
|
8652
|
+
if (index !== -1) {
|
|
8653
|
+
history[index] = item;
|
|
8654
|
+
} else {
|
|
8655
|
+
history.push(item);
|
|
8656
|
+
}
|
|
8657
|
+
this.writeLocalFile(this.historyFile, history);
|
|
8658
|
+
}
|
|
8659
|
+
}
|
|
8660
|
+
async getHistory(sessionId) {
|
|
8661
|
+
this.checkHistoryEnabled();
|
|
8662
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8663
|
+
const pool = await this.getPGPool();
|
|
8664
|
+
const res = await pool.query(
|
|
8665
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
8666
|
+
FROM ${this.historyTableName}
|
|
8667
|
+
WHERE session_id = $1
|
|
8668
|
+
ORDER BY created_at ASC`,
|
|
8669
|
+
[sessionId]
|
|
8670
|
+
);
|
|
8671
|
+
return res.rows;
|
|
8672
|
+
} else if (this.provider === "mongodb") {
|
|
8673
|
+
await this.getMongoClient();
|
|
8674
|
+
const db = this.getMongoDb();
|
|
8675
|
+
const col = db.collection(this.historyTableName);
|
|
8676
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
8677
|
+
return items.map((item) => ({
|
|
8678
|
+
id: item.id,
|
|
8679
|
+
role: item.role,
|
|
8680
|
+
content: item.content,
|
|
8681
|
+
sources: item.sources,
|
|
8682
|
+
uiTransformation: item.ui_transformation,
|
|
8683
|
+
trace: item.trace,
|
|
8684
|
+
createdAt: item.created_at
|
|
8685
|
+
}));
|
|
8686
|
+
} else {
|
|
8687
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8688
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
async clearHistory(sessionId) {
|
|
8692
|
+
this.checkHistoryEnabled();
|
|
8693
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8694
|
+
const pool = await this.getPGPool();
|
|
8695
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
8696
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
8697
|
+
} else if (this.provider === "mongodb") {
|
|
8698
|
+
await this.getMongoClient();
|
|
8699
|
+
const db = this.getMongoDb();
|
|
8700
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
8701
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
8702
|
+
} else {
|
|
8703
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8704
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
8705
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
8706
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
8707
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
8708
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
8709
|
+
}
|
|
8710
|
+
}
|
|
8711
|
+
async listSessions() {
|
|
8712
|
+
this.checkHistoryEnabled();
|
|
8713
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8714
|
+
const pool = await this.getPGPool();
|
|
8715
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
8716
|
+
return res.rows.map((r) => r.session_id);
|
|
8717
|
+
} else if (this.provider === "mongodb") {
|
|
8718
|
+
await this.getMongoClient();
|
|
8719
|
+
const db = this.getMongoDb();
|
|
8720
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
8721
|
+
} else {
|
|
8722
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8723
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
8724
|
+
return Array.from(sessions);
|
|
8725
|
+
}
|
|
8726
|
+
}
|
|
8727
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
8728
|
+
async saveFeedback(feedback) {
|
|
8729
|
+
this.checkFeedbackEnabled();
|
|
8730
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8731
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8732
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8733
|
+
const pool = await this.getPGPool();
|
|
8734
|
+
await pool.query(
|
|
8735
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
8736
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
8737
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
8738
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
8739
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
8740
|
+
);
|
|
8741
|
+
} else if (this.provider === "mongodb") {
|
|
8742
|
+
await this.getMongoClient();
|
|
8743
|
+
const db = this.getMongoDb();
|
|
8744
|
+
const col = db.collection(this.feedbackTableName);
|
|
8745
|
+
await col.updateOne(
|
|
8746
|
+
{ message_id: feedback.messageId },
|
|
8747
|
+
{
|
|
8748
|
+
$set: {
|
|
8749
|
+
id,
|
|
8750
|
+
message_id: feedback.messageId,
|
|
8751
|
+
session_id: feedback.sessionId,
|
|
8752
|
+
rating: feedback.rating,
|
|
8753
|
+
comment: feedback.comment || null,
|
|
8754
|
+
created_at: createdAt
|
|
8755
|
+
}
|
|
8756
|
+
},
|
|
8757
|
+
{ upsert: true }
|
|
8758
|
+
);
|
|
8759
|
+
} else {
|
|
8760
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8761
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
8762
|
+
const item = {
|
|
8763
|
+
id,
|
|
8764
|
+
message_id: feedback.messageId,
|
|
8765
|
+
session_id: feedback.sessionId,
|
|
8766
|
+
rating: feedback.rating,
|
|
8767
|
+
comment: feedback.comment || null,
|
|
8768
|
+
created_at: createdAt
|
|
8769
|
+
};
|
|
8770
|
+
if (index !== -1) {
|
|
8771
|
+
list[index] = item;
|
|
8772
|
+
} else {
|
|
8773
|
+
list.push(item);
|
|
8774
|
+
}
|
|
8775
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
8776
|
+
}
|
|
8777
|
+
}
|
|
8778
|
+
async getFeedback(messageId) {
|
|
8779
|
+
this.checkFeedbackEnabled();
|
|
8780
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8781
|
+
const pool = await this.getPGPool();
|
|
8782
|
+
const res = await pool.query(
|
|
8783
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8784
|
+
FROM ${this.feedbackTableName}
|
|
8785
|
+
WHERE message_id = $1`,
|
|
8786
|
+
[messageId]
|
|
8787
|
+
);
|
|
8788
|
+
return res.rows[0] || null;
|
|
8789
|
+
} else if (this.provider === "mongodb") {
|
|
8790
|
+
await this.getMongoClient();
|
|
8791
|
+
const db = this.getMongoDb();
|
|
8792
|
+
const col = db.collection(this.feedbackTableName);
|
|
8793
|
+
const item = await col.findOne({ message_id: messageId });
|
|
8794
|
+
if (!item) return null;
|
|
8795
|
+
return {
|
|
8796
|
+
id: item.id,
|
|
8797
|
+
messageId: item.message_id,
|
|
8798
|
+
sessionId: item.session_id,
|
|
8799
|
+
rating: item.rating,
|
|
8800
|
+
comment: item.comment,
|
|
8801
|
+
createdAt: item.created_at
|
|
8802
|
+
};
|
|
8803
|
+
} else {
|
|
8804
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8805
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
8806
|
+
}
|
|
8807
|
+
}
|
|
8808
|
+
async listFeedback() {
|
|
8809
|
+
this.checkFeedbackEnabled();
|
|
8810
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8811
|
+
const pool = await this.getPGPool();
|
|
8812
|
+
const res = await pool.query(
|
|
8813
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8814
|
+
FROM ${this.feedbackTableName}
|
|
8815
|
+
ORDER BY created_at DESC`
|
|
8816
|
+
);
|
|
8817
|
+
return res.rows;
|
|
8818
|
+
} else if (this.provider === "mongodb") {
|
|
8819
|
+
await this.getMongoClient();
|
|
8820
|
+
const db = this.getMongoDb();
|
|
8821
|
+
const col = db.collection(this.feedbackTableName);
|
|
8822
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
8823
|
+
return items.map((item) => ({
|
|
8824
|
+
id: item.id,
|
|
8825
|
+
messageId: item.message_id,
|
|
8826
|
+
sessionId: item.session_id,
|
|
8827
|
+
rating: item.rating,
|
|
8828
|
+
comment: item.comment,
|
|
8829
|
+
createdAt: item.created_at
|
|
8830
|
+
}));
|
|
8831
|
+
} else {
|
|
8832
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8833
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
async disconnect() {
|
|
8837
|
+
if (this.pgPool) {
|
|
8838
|
+
await this.pgPool.end();
|
|
8839
|
+
this.pgPool = null;
|
|
8840
|
+
}
|
|
8841
|
+
if (this.mongoClient) {
|
|
8842
|
+
await this.mongoClient.close();
|
|
8843
|
+
this.mongoClient = null;
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
};
|
|
8847
|
+
|
|
7289
8848
|
// src/handlers/index.ts
|
|
8849
|
+
async function checkAuth(req, onAuthorize) {
|
|
8850
|
+
if (!onAuthorize) return null;
|
|
8851
|
+
try {
|
|
8852
|
+
const res = await onAuthorize(req);
|
|
8853
|
+
if (res === false) {
|
|
8854
|
+
return import_server.NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
8855
|
+
}
|
|
8856
|
+
if (res instanceof Response) {
|
|
8857
|
+
return res;
|
|
8858
|
+
}
|
|
8859
|
+
return null;
|
|
8860
|
+
} catch (err) {
|
|
8861
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
8862
|
+
return import_server.NextResponse.json({ error: msg }, { status: 401 });
|
|
8863
|
+
}
|
|
8864
|
+
}
|
|
8865
|
+
var RateLimiter = class {
|
|
8866
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
8867
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
8868
|
+
this.windowMs = windowMs;
|
|
8869
|
+
this.max = max;
|
|
8870
|
+
}
|
|
8871
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
8872
|
+
allow(key) {
|
|
8873
|
+
const now = Date.now();
|
|
8874
|
+
const cutoff = now - this.windowMs;
|
|
8875
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8876
|
+
existing.push(now);
|
|
8877
|
+
this.hits.set(key, existing);
|
|
8878
|
+
if (this.hits.size > 5e3) {
|
|
8879
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
8880
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
8881
|
+
}
|
|
8882
|
+
}
|
|
8883
|
+
return existing.length <= this.max;
|
|
8884
|
+
}
|
|
8885
|
+
retryAfterSec(key) {
|
|
8886
|
+
const now = Date.now();
|
|
8887
|
+
const cutoff = now - this.windowMs;
|
|
8888
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8889
|
+
if (existing.length === 0) return 0;
|
|
8890
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
8891
|
+
}
|
|
8892
|
+
};
|
|
8893
|
+
var _g = global;
|
|
8894
|
+
var _a;
|
|
8895
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
8896
|
+
function getRateLimitKey(req) {
|
|
8897
|
+
var _a2, _b;
|
|
8898
|
+
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";
|
|
8899
|
+
return `ip:${ip}`;
|
|
8900
|
+
}
|
|
8901
|
+
function checkRateLimit(req) {
|
|
8902
|
+
const key = getRateLimitKey(req);
|
|
8903
|
+
if (!rateLimiter.allow(key)) {
|
|
8904
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
8905
|
+
return new Response(
|
|
8906
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
8907
|
+
{
|
|
8908
|
+
status: 429,
|
|
8909
|
+
headers: {
|
|
8910
|
+
"Content-Type": "application/json",
|
|
8911
|
+
"Retry-After": String(retryAfter),
|
|
8912
|
+
"X-RateLimit-Limit": "30",
|
|
8913
|
+
"X-RateLimit-Window": "60"
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
);
|
|
8917
|
+
}
|
|
8918
|
+
return null;
|
|
8919
|
+
}
|
|
8920
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
8921
|
+
function sanitizeInput(raw) {
|
|
8922
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
8923
|
+
const trimmed = stripped.trim();
|
|
8924
|
+
if (!trimmed) {
|
|
8925
|
+
return { ok: false, error: "message must not be empty" };
|
|
8926
|
+
}
|
|
8927
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
8928
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
8929
|
+
}
|
|
8930
|
+
return { ok: true, value: trimmed };
|
|
8931
|
+
}
|
|
8932
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
8933
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
8934
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
8935
|
+
if (!_g[cacheKey]) {
|
|
8936
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
8937
|
+
}
|
|
8938
|
+
return _g[cacheKey];
|
|
8939
|
+
}
|
|
7290
8940
|
function sseFrame(payload) {
|
|
7291
8941
|
return `data: ${JSON.stringify(payload)}
|
|
7292
8942
|
|
|
@@ -7324,47 +8974,88 @@ var SSE_HEADERS = {
|
|
|
7324
8974
|
"X-Accel-Buffering": "no"
|
|
7325
8975
|
// Disable Nginx buffering for streaming
|
|
7326
8976
|
};
|
|
7327
|
-
function createChatHandler(configOrPlugin) {
|
|
7328
|
-
const plugin =
|
|
8977
|
+
function createChatHandler(configOrPlugin, options) {
|
|
8978
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
8979
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
8980
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7329
8981
|
return async function POST(req) {
|
|
8982
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
8983
|
+
if (authResult) return authResult;
|
|
8984
|
+
const rateLimited = checkRateLimit(req);
|
|
8985
|
+
if (rateLimited) return rateLimited;
|
|
7330
8986
|
try {
|
|
7331
8987
|
const body = await req.json();
|
|
7332
|
-
const { message, history = [], namespace } = body;
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
8988
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
8989
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
8990
|
+
if (!sanitized.ok) {
|
|
8991
|
+
return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
8992
|
+
}
|
|
8993
|
+
const message = sanitized.value;
|
|
8994
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8995
|
+
await storage.saveMessage(sessionId, {
|
|
8996
|
+
id: userMsgId,
|
|
8997
|
+
role: "user",
|
|
8998
|
+
content: message
|
|
8999
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7336
9000
|
const result = await plugin.chat(message, history, namespace);
|
|
7337
|
-
|
|
9001
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9002
|
+
await storage.saveMessage(sessionId, {
|
|
9003
|
+
id: assistantMsgId,
|
|
9004
|
+
role: "assistant",
|
|
9005
|
+
content: result.reply,
|
|
9006
|
+
sources: result.sources,
|
|
9007
|
+
uiTransformation: result.ui_transformation,
|
|
9008
|
+
trace: result.trace
|
|
9009
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9010
|
+
return import_server.NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9011
|
+
messageId: assistantMsgId,
|
|
9012
|
+
userMessageId: userMsgId
|
|
9013
|
+
}));
|
|
7338
9014
|
} catch (err) {
|
|
7339
9015
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7340
9016
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
7341
9017
|
}
|
|
7342
9018
|
};
|
|
7343
9019
|
}
|
|
7344
|
-
function createStreamHandler(configOrPlugin) {
|
|
7345
|
-
const plugin =
|
|
9020
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9021
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9022
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9023
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7346
9024
|
return async function POST(req) {
|
|
9025
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9026
|
+
if (authResult) return authResult;
|
|
9027
|
+
const rateLimited = checkRateLimit(req);
|
|
9028
|
+
if (rateLimited) return rateLimited;
|
|
7347
9029
|
let body;
|
|
7348
9030
|
try {
|
|
7349
9031
|
body = await req.json();
|
|
7350
9032
|
} catch (e) {
|
|
7351
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9033
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7352
9034
|
status: 400,
|
|
7353
9035
|
headers: { "Content-Type": "application/json" }
|
|
7354
9036
|
});
|
|
7355
9037
|
}
|
|
7356
|
-
const { message, history = [], namespace } = body;
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
9038
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9039
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9040
|
+
if (!sanitized.ok) {
|
|
9041
|
+
return new Response(
|
|
9042
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9043
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9044
|
+
);
|
|
7362
9045
|
}
|
|
9046
|
+
const message = sanitized.value;
|
|
9047
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9048
|
+
await storage.saveMessage(sessionId, {
|
|
9049
|
+
id: userMsgId,
|
|
9050
|
+
role: "user",
|
|
9051
|
+
content: message
|
|
9052
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9053
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7363
9054
|
const encoder = new TextEncoder();
|
|
7364
9055
|
let isActive = true;
|
|
7365
9056
|
const stream = new ReadableStream({
|
|
7366
9057
|
async start(controller) {
|
|
7367
|
-
var
|
|
9058
|
+
var _a2;
|
|
7368
9059
|
const enqueue = (text) => {
|
|
7369
9060
|
if (!isActive) return;
|
|
7370
9061
|
try {
|
|
@@ -7375,11 +9066,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7375
9066
|
};
|
|
7376
9067
|
try {
|
|
7377
9068
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9069
|
+
let fullReply = "";
|
|
7378
9070
|
try {
|
|
7379
9071
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7380
9072
|
const chunk = temp.value;
|
|
7381
9073
|
if (!isActive) break;
|
|
7382
9074
|
if (typeof chunk === "string") {
|
|
9075
|
+
fullReply += chunk;
|
|
7383
9076
|
enqueue(sseTextFrame(chunk));
|
|
7384
9077
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7385
9078
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7392,9 +9085,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7392
9085
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7393
9086
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7394
9087
|
}
|
|
9088
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7395
9089
|
if (sources.length > 0) {
|
|
7396
9090
|
try {
|
|
7397
|
-
|
|
9091
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7398
9092
|
if (uiTransformation) {
|
|
7399
9093
|
enqueue(sseUIFrame(uiTransformation));
|
|
7400
9094
|
}
|
|
@@ -7402,11 +9096,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7402
9096
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7403
9097
|
try {
|
|
7404
9098
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7405
|
-
if (fallback)
|
|
9099
|
+
if (fallback) {
|
|
9100
|
+
uiTransformation = fallback;
|
|
9101
|
+
enqueue(sseUIFrame(fallback));
|
|
9102
|
+
}
|
|
7406
9103
|
} catch (e) {
|
|
7407
9104
|
}
|
|
7408
9105
|
}
|
|
7409
9106
|
}
|
|
9107
|
+
await storage.saveMessage(sessionId, {
|
|
9108
|
+
id: assistantMsgId,
|
|
9109
|
+
role: "assistant",
|
|
9110
|
+
content: fullReply,
|
|
9111
|
+
sources,
|
|
9112
|
+
uiTransformation,
|
|
9113
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9114
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7410
9115
|
}
|
|
7411
9116
|
}
|
|
7412
9117
|
} catch (temp) {
|
|
@@ -7443,12 +9148,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7443
9148
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7444
9149
|
}
|
|
7445
9150
|
});
|
|
7446
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9151
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7447
9152
|
};
|
|
7448
9153
|
}
|
|
7449
|
-
function createIngestHandler(configOrPlugin) {
|
|
7450
|
-
const plugin =
|
|
9154
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9155
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9156
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7451
9157
|
return async function POST(req) {
|
|
9158
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9159
|
+
if (authResult) return authResult;
|
|
7452
9160
|
try {
|
|
7453
9161
|
const body = await req.json();
|
|
7454
9162
|
const { documents, namespace } = body;
|
|
@@ -7463,9 +9171,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7463
9171
|
}
|
|
7464
9172
|
};
|
|
7465
9173
|
}
|
|
7466
|
-
function createHealthHandler(configOrPlugin) {
|
|
7467
|
-
const plugin =
|
|
7468
|
-
|
|
9174
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9175
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9176
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9177
|
+
return async function GET(req) {
|
|
9178
|
+
if (req) {
|
|
9179
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9180
|
+
if (authResult) return authResult;
|
|
9181
|
+
}
|
|
7469
9182
|
try {
|
|
7470
9183
|
const health = await plugin.checkHealth();
|
|
7471
9184
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7480,9 +9193,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7480
9193
|
}
|
|
7481
9194
|
};
|
|
7482
9195
|
}
|
|
7483
|
-
function createUploadHandler(configOrPlugin) {
|
|
7484
|
-
const plugin =
|
|
9196
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9197
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9198
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7485
9199
|
return async function POST(req) {
|
|
9200
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9201
|
+
if (authResult) return authResult;
|
|
7486
9202
|
try {
|
|
7487
9203
|
const formData = await req.formData();
|
|
7488
9204
|
const files = formData.getAll("files");
|
|
@@ -7556,9 +9272,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7556
9272
|
}
|
|
7557
9273
|
};
|
|
7558
9274
|
}
|
|
7559
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
7560
|
-
const plugin =
|
|
9275
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9276
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9277
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7561
9278
|
return async function POST(req) {
|
|
9279
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9280
|
+
if (authResult) return authResult;
|
|
7562
9281
|
try {
|
|
7563
9282
|
const body = await req.json();
|
|
7564
9283
|
const { query, namespace } = body;
|
|
@@ -7573,11 +9292,179 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
7573
9292
|
}
|
|
7574
9293
|
};
|
|
7575
9294
|
}
|
|
9295
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9296
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9297
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9298
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9299
|
+
return async function handler(req) {
|
|
9300
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9301
|
+
if (authResult) return authResult;
|
|
9302
|
+
const url = new URL(req.url);
|
|
9303
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9304
|
+
if (req.method === "GET") {
|
|
9305
|
+
try {
|
|
9306
|
+
const history = await storage.getHistory(sessionId);
|
|
9307
|
+
return import_server.NextResponse.json({ history });
|
|
9308
|
+
} catch (err) {
|
|
9309
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9310
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9311
|
+
}
|
|
9312
|
+
} else if (req.method === "POST") {
|
|
9313
|
+
try {
|
|
9314
|
+
const body = await req.json().catch(() => ({}));
|
|
9315
|
+
const sid = body.sessionId || sessionId;
|
|
9316
|
+
await storage.clearHistory(sid);
|
|
9317
|
+
return import_server.NextResponse.json({ success: true });
|
|
9318
|
+
} catch (err) {
|
|
9319
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9320
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9323
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9324
|
+
};
|
|
9325
|
+
}
|
|
9326
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9327
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9328
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9329
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9330
|
+
return async function handler(req) {
|
|
9331
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9332
|
+
if (authResult) return authResult;
|
|
9333
|
+
if (req.method === "GET") {
|
|
9334
|
+
try {
|
|
9335
|
+
const url = new URL(req.url);
|
|
9336
|
+
const messageId = url.searchParams.get("messageId");
|
|
9337
|
+
if (!messageId) {
|
|
9338
|
+
const feedbackList = await storage.listFeedback();
|
|
9339
|
+
return import_server.NextResponse.json({ feedback: feedbackList });
|
|
9340
|
+
}
|
|
9341
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9342
|
+
return import_server.NextResponse.json({ feedback });
|
|
9343
|
+
} catch (err) {
|
|
9344
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9345
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9346
|
+
}
|
|
9347
|
+
} else if (req.method === "POST") {
|
|
9348
|
+
try {
|
|
9349
|
+
const body = await req.json();
|
|
9350
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9351
|
+
if (!messageId) {
|
|
9352
|
+
return import_server.NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9353
|
+
}
|
|
9354
|
+
if (!rating) {
|
|
9355
|
+
return import_server.NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9356
|
+
}
|
|
9357
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9358
|
+
return import_server.NextResponse.json({ success: true });
|
|
9359
|
+
} catch (err) {
|
|
9360
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9361
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9362
|
+
}
|
|
9363
|
+
}
|
|
9364
|
+
return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9365
|
+
};
|
|
9366
|
+
}
|
|
9367
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9368
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9369
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9370
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9371
|
+
return async function GET(req) {
|
|
9372
|
+
if (req) {
|
|
9373
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9374
|
+
if (authResult) return authResult;
|
|
9375
|
+
}
|
|
9376
|
+
void req;
|
|
9377
|
+
try {
|
|
9378
|
+
const sessions = await storage.listSessions();
|
|
9379
|
+
return import_server.NextResponse.json({ sessions });
|
|
9380
|
+
} catch (err) {
|
|
9381
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9382
|
+
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
9383
|
+
}
|
|
9384
|
+
};
|
|
9385
|
+
}
|
|
9386
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9387
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9388
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9389
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9390
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9391
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9392
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9393
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9394
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9395
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9396
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
9397
|
+
async function routePostRequest(req, segment) {
|
|
9398
|
+
switch (segment) {
|
|
9399
|
+
case "chat":
|
|
9400
|
+
return streamHandler(req);
|
|
9401
|
+
case "chat-sync":
|
|
9402
|
+
return chatHandler(req);
|
|
9403
|
+
case "upload":
|
|
9404
|
+
return uploadHandler(req);
|
|
9405
|
+
case "suggestions":
|
|
9406
|
+
return suggestionsHandler(req);
|
|
9407
|
+
case "health":
|
|
9408
|
+
return healthHandler(req);
|
|
9409
|
+
case "history":
|
|
9410
|
+
case "history/clear":
|
|
9411
|
+
return historyHandler(req);
|
|
9412
|
+
case "feedback":
|
|
9413
|
+
return feedbackHandler(req);
|
|
9414
|
+
default:
|
|
9415
|
+
return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9418
|
+
async function routeGetRequest(req, segment) {
|
|
9419
|
+
switch (segment) {
|
|
9420
|
+
case "health":
|
|
9421
|
+
return healthHandler(req);
|
|
9422
|
+
case "history":
|
|
9423
|
+
return historyHandler(req);
|
|
9424
|
+
case "feedback":
|
|
9425
|
+
return feedbackHandler(req);
|
|
9426
|
+
case "sessions":
|
|
9427
|
+
return sessionsHandler(req);
|
|
9428
|
+
default:
|
|
9429
|
+
return import_server.NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
async function getSegment(context) {
|
|
9433
|
+
var _a2;
|
|
9434
|
+
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;
|
|
9435
|
+
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
9436
|
+
return segments.join("/") || "chat";
|
|
9437
|
+
}
|
|
9438
|
+
return {
|
|
9439
|
+
GET: async (req, context) => {
|
|
9440
|
+
try {
|
|
9441
|
+
const segment = await getSegment(context);
|
|
9442
|
+
return await routeGetRequest(req, segment);
|
|
9443
|
+
} catch (err) {
|
|
9444
|
+
const msg = err instanceof Error ? err.message : "GET Routing failed";
|
|
9445
|
+
return import_server.NextResponse.json({ error: msg }, { status: 500 });
|
|
9446
|
+
}
|
|
9447
|
+
},
|
|
9448
|
+
POST: async (req, context) => {
|
|
9449
|
+
try {
|
|
9450
|
+
const segment = await getSegment(context);
|
|
9451
|
+
return await routePostRequest(req, segment);
|
|
9452
|
+
} catch (err) {
|
|
9453
|
+
const msg = err instanceof Error ? err.message : "POST Routing failed";
|
|
9454
|
+
return import_server.NextResponse.json({ error: msg }, { status: 500 });
|
|
9455
|
+
}
|
|
9456
|
+
}
|
|
9457
|
+
};
|
|
9458
|
+
}
|
|
7576
9459
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7577
9460
|
0 && (module.exports = {
|
|
7578
9461
|
createChatHandler,
|
|
9462
|
+
createFeedbackHandler,
|
|
7579
9463
|
createHealthHandler,
|
|
9464
|
+
createHistoryHandler,
|
|
7580
9465
|
createIngestHandler,
|
|
9466
|
+
createRagHandler,
|
|
9467
|
+
createSessionsHandler,
|
|
7581
9468
|
createStreamHandler,
|
|
7582
9469
|
createSuggestionsHandler,
|
|
7583
9470
|
createUploadHandler,
|