@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/server.mjs
CHANGED
|
@@ -6,9 +6,6 @@ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
7
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
8
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
9
|
-
var __typeError = (msg) => {
|
|
10
|
-
throw TypeError(msg);
|
|
11
|
-
};
|
|
12
9
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
10
|
var __spreadValues = (a, b) => {
|
|
14
11
|
for (var prop in b || (b = {}))
|
|
@@ -56,43 +53,15 @@ var __asyncGenerator = (__this, __arguments, generator) => {
|
|
|
56
53
|
}, 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 = {};
|
|
57
54
|
return generator = generator.apply(__this, __arguments), it[__knownSymbol("asyncIterator")] = () => it, method("next"), method("throw"), method("return"), it;
|
|
58
55
|
};
|
|
59
|
-
var __yieldStar = (value) => {
|
|
60
|
-
var obj = value[__knownSymbol("asyncIterator")], isAwait = false, method, it = {};
|
|
61
|
-
if (obj == null) {
|
|
62
|
-
obj = value[__knownSymbol("iterator")]();
|
|
63
|
-
method = (k) => it[k] = (x) => obj[k](x);
|
|
64
|
-
} else {
|
|
65
|
-
obj = obj.call(value);
|
|
66
|
-
method = (k) => it[k] = (v) => {
|
|
67
|
-
if (isAwait) {
|
|
68
|
-
isAwait = false;
|
|
69
|
-
if (k === "throw") throw v;
|
|
70
|
-
return v;
|
|
71
|
-
}
|
|
72
|
-
isAwait = true;
|
|
73
|
-
return {
|
|
74
|
-
done: false,
|
|
75
|
-
value: new __await(new Promise((resolve) => {
|
|
76
|
-
var x = obj[k](v);
|
|
77
|
-
if (!(x instanceof Object)) __typeError("Object expected");
|
|
78
|
-
resolve(x);
|
|
79
|
-
}), 1)
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
|
|
84
|
-
throw x;
|
|
85
|
-
}, "return" in obj && method("return"), it;
|
|
86
|
-
};
|
|
87
56
|
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);
|
|
88
57
|
|
|
89
58
|
// src/utils/templateUtils.ts
|
|
90
59
|
function isRecord(value) {
|
|
91
60
|
return typeof value === "object" && value !== null;
|
|
92
61
|
}
|
|
93
|
-
function resolvePath(obj,
|
|
94
|
-
if (!
|
|
95
|
-
return
|
|
62
|
+
function resolvePath(obj, path2) {
|
|
63
|
+
if (!path2 || !obj) return void 0;
|
|
64
|
+
return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
|
|
96
65
|
if (!isRecord(current) && !Array.isArray(current)) {
|
|
97
66
|
return void 0;
|
|
98
67
|
}
|
|
@@ -202,7 +171,7 @@ var init_PineconeProvider = __esm({
|
|
|
202
171
|
static getHealthChecker() {
|
|
203
172
|
return {
|
|
204
173
|
async check(config) {
|
|
205
|
-
var
|
|
174
|
+
var _a2, _b;
|
|
206
175
|
const opts = config.options || {};
|
|
207
176
|
const indexName = config.indexName;
|
|
208
177
|
const timestamp = Date.now();
|
|
@@ -210,7 +179,7 @@ var init_PineconeProvider = __esm({
|
|
|
210
179
|
const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
|
|
211
180
|
const client = new Pinecone2({ apiKey: opts.apiKey });
|
|
212
181
|
const indexes = await client.listIndexes();
|
|
213
|
-
const indexNames = (_b = (
|
|
182
|
+
const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
214
183
|
if (!indexNames.includes(indexName)) {
|
|
215
184
|
return {
|
|
216
185
|
healthy: false,
|
|
@@ -237,10 +206,10 @@ var init_PineconeProvider = __esm({
|
|
|
237
206
|
};
|
|
238
207
|
}
|
|
239
208
|
async initialize() {
|
|
240
|
-
var
|
|
209
|
+
var _a2, _b;
|
|
241
210
|
this.client = new Pinecone({ apiKey: this.apiKey });
|
|
242
211
|
const indexes = await this.client.listIndexes();
|
|
243
|
-
const names = (_b = (
|
|
212
|
+
const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
244
213
|
if (!names.includes(this.indexName)) {
|
|
245
214
|
throw new Error(
|
|
246
215
|
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
@@ -252,12 +221,12 @@ var init_PineconeProvider = __esm({
|
|
|
252
221
|
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
253
222
|
}
|
|
254
223
|
async upsert(doc, namespace) {
|
|
255
|
-
var
|
|
224
|
+
var _a2;
|
|
256
225
|
await this.index(namespace).upsert({
|
|
257
226
|
records: [{
|
|
258
227
|
id: String(doc.id),
|
|
259
228
|
values: doc.vector,
|
|
260
|
-
metadata: __spreadValues({ content: doc.content }, (
|
|
229
|
+
metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
|
|
261
230
|
}]
|
|
262
231
|
});
|
|
263
232
|
}
|
|
@@ -265,29 +234,29 @@ var init_PineconeProvider = __esm({
|
|
|
265
234
|
const BATCH = 100;
|
|
266
235
|
for (let i = 0; i < docs.length; i += BATCH) {
|
|
267
236
|
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
268
|
-
var
|
|
237
|
+
var _a2;
|
|
269
238
|
return {
|
|
270
239
|
id: String(d.id),
|
|
271
240
|
values: d.vector,
|
|
272
|
-
metadata: __spreadValues({ content: d.content }, (
|
|
241
|
+
metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
|
|
273
242
|
};
|
|
274
243
|
});
|
|
275
244
|
await this.index(namespace).upsert({ records });
|
|
276
245
|
}
|
|
277
246
|
}
|
|
278
247
|
async query(vector, topK, namespace, filter) {
|
|
279
|
-
var
|
|
248
|
+
var _a2;
|
|
280
249
|
const pineconeFilter = this.sanitizeFilter(filter);
|
|
281
250
|
const result = await this.index(namespace).query(__spreadValues({
|
|
282
251
|
vector,
|
|
283
252
|
topK,
|
|
284
253
|
includeMetadata: true
|
|
285
254
|
}, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
|
|
286
|
-
return ((
|
|
287
|
-
var
|
|
255
|
+
return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
|
|
256
|
+
var _a3, _b;
|
|
288
257
|
return {
|
|
289
258
|
id: m.id,
|
|
290
|
-
score: (
|
|
259
|
+
score: (_a3 = m.score) != null ? _a3 : 0,
|
|
291
260
|
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
292
261
|
metadata: m.metadata
|
|
293
262
|
};
|
|
@@ -326,13 +295,13 @@ var init_PostgreSQLProvider = __esm({
|
|
|
326
295
|
init_BaseVectorProvider();
|
|
327
296
|
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
328
297
|
constructor(config) {
|
|
329
|
-
var
|
|
298
|
+
var _a2;
|
|
330
299
|
super(config);
|
|
331
300
|
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
332
301
|
const opts = config.options;
|
|
333
302
|
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
334
303
|
this.connectionString = opts.connectionString;
|
|
335
|
-
this.dimensions = (
|
|
304
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
|
|
336
305
|
}
|
|
337
306
|
static getValidator() {
|
|
338
307
|
return {
|
|
@@ -413,7 +382,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
413
382
|
}
|
|
414
383
|
}
|
|
415
384
|
async upsert(doc, namespace = "") {
|
|
416
|
-
var
|
|
385
|
+
var _a2;
|
|
417
386
|
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
418
387
|
await this.pool.query(
|
|
419
388
|
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
@@ -423,7 +392,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
423
392
|
content = EXCLUDED.content,
|
|
424
393
|
metadata = EXCLUDED.metadata,
|
|
425
394
|
embedding = EXCLUDED.embedding`,
|
|
426
|
-
[doc.id, namespace, doc.content, JSON.stringify((
|
|
395
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
|
|
427
396
|
);
|
|
428
397
|
}
|
|
429
398
|
async batchUpsert(docs, namespace = "") {
|
|
@@ -436,9 +405,9 @@ var init_PostgreSQLProvider = __esm({
|
|
|
436
405
|
const batch = docs.slice(i, i + BATCH_SIZE);
|
|
437
406
|
const values = [];
|
|
438
407
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
439
|
-
var
|
|
408
|
+
var _a2;
|
|
440
409
|
const offset = idx * 5;
|
|
441
|
-
values.push(doc.id, namespace, doc.content, JSON.stringify((
|
|
410
|
+
values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
|
|
442
411
|
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
|
|
443
412
|
}).join(", ");
|
|
444
413
|
const query = `
|
|
@@ -521,8 +490,8 @@ var init_PostgreSQLProvider = __esm({
|
|
|
521
490
|
|
|
522
491
|
// src/utils/synonyms.ts
|
|
523
492
|
function resolveMetadataValue(meta, uiKey) {
|
|
524
|
-
var
|
|
525
|
-
const synonyms = (
|
|
493
|
+
var _a2;
|
|
494
|
+
const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
|
|
526
495
|
const keys = Object.keys(meta);
|
|
527
496
|
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
528
497
|
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
@@ -609,14 +578,14 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
609
578
|
init_synonyms();
|
|
610
579
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
611
580
|
constructor(config) {
|
|
612
|
-
var
|
|
581
|
+
var _a2, _b, _c;
|
|
613
582
|
super(config);
|
|
614
583
|
const opts = config.options || {};
|
|
615
584
|
if (!opts.connectionString) {
|
|
616
585
|
throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
|
|
617
586
|
}
|
|
618
587
|
this.connectionString = opts.connectionString;
|
|
619
|
-
this.dimensions = (
|
|
588
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
|
|
620
589
|
this.tables = [];
|
|
621
590
|
const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
|
|
622
591
|
this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
|
|
@@ -674,11 +643,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
674
643
|
* Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
|
|
675
644
|
*/
|
|
676
645
|
async batchUpsert(docs, namespace = "") {
|
|
677
|
-
var
|
|
646
|
+
var _a2;
|
|
678
647
|
if (docs.length === 0) return;
|
|
679
648
|
const docsByFile = {};
|
|
680
649
|
for (const doc of docs) {
|
|
681
|
-
const fileName = ((
|
|
650
|
+
const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
|
|
682
651
|
if (!docsByFile[fileName]) docsByFile[fileName] = [];
|
|
683
652
|
docsByFile[fileName].push(doc);
|
|
684
653
|
}
|
|
@@ -731,11 +700,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
731
700
|
const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
|
|
732
701
|
const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
|
|
733
702
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
734
|
-
var
|
|
703
|
+
var _a3, _b;
|
|
735
704
|
const offset = idx * (5 + csvHeaders.length);
|
|
736
705
|
values.push(doc.id);
|
|
737
706
|
for (const h of csvHeaders) {
|
|
738
|
-
values.push(String(((
|
|
707
|
+
values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
|
|
739
708
|
}
|
|
740
709
|
values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
|
|
741
710
|
const docPlaceholders = [];
|
|
@@ -774,7 +743,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
774
743
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
775
744
|
*/
|
|
776
745
|
async query(vector, topK, _namespace, _filter) {
|
|
777
|
-
var
|
|
746
|
+
var _a2;
|
|
778
747
|
if (!this.pool) {
|
|
779
748
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
780
749
|
}
|
|
@@ -805,11 +774,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
805
774
|
const filterParams = [];
|
|
806
775
|
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
807
776
|
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
808
|
-
var
|
|
777
|
+
var _a4;
|
|
809
778
|
filterParams.push(String(val));
|
|
810
779
|
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
811
780
|
const paramIdx = baseOffset + filterParams.length;
|
|
812
|
-
const synonyms = (
|
|
781
|
+
const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
|
|
813
782
|
const keysToCheck = [key, ...synonyms];
|
|
814
783
|
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
815
784
|
`metadata->>'${k}'`,
|
|
@@ -878,7 +847,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
878
847
|
}
|
|
879
848
|
const tableResults = [];
|
|
880
849
|
for (const row of result.rows) {
|
|
881
|
-
const
|
|
850
|
+
const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
|
|
882
851
|
delete rest.embedding;
|
|
883
852
|
delete rest.vector_score;
|
|
884
853
|
delete rest.keyword_score;
|
|
@@ -907,10 +876,10 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
907
876
|
}
|
|
908
877
|
allResults.sort((a, b) => b.score - a.score);
|
|
909
878
|
if (allResults.length === 0) return [];
|
|
910
|
-
const bestMatchTable = (
|
|
879
|
+
const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
|
|
911
880
|
const finalSorted = allResults.filter((res) => {
|
|
912
|
-
var
|
|
913
|
-
return ((
|
|
881
|
+
var _a3;
|
|
882
|
+
return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
|
|
914
883
|
});
|
|
915
884
|
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
916
885
|
console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
@@ -1315,14 +1284,14 @@ var init_QdrantProvider = __esm({
|
|
|
1315
1284
|
* Samples points from the collection to discover available payload fields.
|
|
1316
1285
|
*/
|
|
1317
1286
|
async discoverSchema() {
|
|
1318
|
-
var
|
|
1287
|
+
var _a2;
|
|
1319
1288
|
try {
|
|
1320
1289
|
const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
|
|
1321
1290
|
limit: 20,
|
|
1322
1291
|
with_payload: true,
|
|
1323
1292
|
with_vector: false
|
|
1324
1293
|
});
|
|
1325
|
-
const points = ((
|
|
1294
|
+
const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
|
|
1326
1295
|
const keys = /* @__PURE__ */ new Set();
|
|
1327
1296
|
for (const point of points) {
|
|
1328
1297
|
const payload = point.payload || {};
|
|
@@ -1348,12 +1317,12 @@ var init_QdrantProvider = __esm({
|
|
|
1348
1317
|
* Ensures the collection exists. Creates it if missing.
|
|
1349
1318
|
*/
|
|
1350
1319
|
async ensureCollection() {
|
|
1351
|
-
var
|
|
1320
|
+
var _a2;
|
|
1352
1321
|
try {
|
|
1353
1322
|
await this.http.get(`/collections/${this.indexName}`);
|
|
1354
1323
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
1355
1324
|
} catch (err) {
|
|
1356
|
-
if (axios4.isAxiosError(err) && ((
|
|
1325
|
+
if (axios4.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1357
1326
|
const opts = this.config.options;
|
|
1358
1327
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1359
1328
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
@@ -1373,7 +1342,7 @@ var init_QdrantProvider = __esm({
|
|
|
1373
1342
|
* Ensures that a payload field has an index.
|
|
1374
1343
|
*/
|
|
1375
1344
|
async ensureIndex(fieldName, schema = "keyword") {
|
|
1376
|
-
var
|
|
1345
|
+
var _a2;
|
|
1377
1346
|
let fullPath = fieldName;
|
|
1378
1347
|
if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
|
|
1379
1348
|
fullPath = `${this.metadataField}.${fieldName}`;
|
|
@@ -1386,7 +1355,7 @@ var init_QdrantProvider = __esm({
|
|
|
1386
1355
|
console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
|
|
1387
1356
|
} catch (err) {
|
|
1388
1357
|
let status;
|
|
1389
|
-
if (axios4.isAxiosError(err)) status = (
|
|
1358
|
+
if (axios4.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
|
|
1390
1359
|
if (status === 409) return;
|
|
1391
1360
|
console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
|
|
1392
1361
|
}
|
|
@@ -1415,7 +1384,7 @@ var init_QdrantProvider = __esm({
|
|
|
1415
1384
|
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
1416
1385
|
}
|
|
1417
1386
|
async query(vector, topK, namespace, _filter) {
|
|
1418
|
-
var
|
|
1387
|
+
var _a2;
|
|
1419
1388
|
const must = [];
|
|
1420
1389
|
if (namespace) {
|
|
1421
1390
|
must.push({ key: "namespace", match: { value: namespace } });
|
|
@@ -1437,7 +1406,7 @@ var init_QdrantProvider = __esm({
|
|
|
1437
1406
|
limit: topK,
|
|
1438
1407
|
with_payload: true,
|
|
1439
1408
|
params: {
|
|
1440
|
-
hnsw_ef: ((
|
|
1409
|
+
hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
|
|
1441
1410
|
exact: false
|
|
1442
1411
|
},
|
|
1443
1412
|
filter: must.length > 0 ? { must } : void 0
|
|
@@ -1532,13 +1501,13 @@ var init_ChromaDBProvider = __esm({
|
|
|
1532
1501
|
* Get or create the ChromaDB collection.
|
|
1533
1502
|
*/
|
|
1534
1503
|
async initialize() {
|
|
1535
|
-
var
|
|
1504
|
+
var _a2;
|
|
1536
1505
|
try {
|
|
1537
1506
|
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1538
1507
|
this.collectionId = data.id;
|
|
1539
1508
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1540
1509
|
} catch (err) {
|
|
1541
|
-
if (axios5.isAxiosError(err) && ((
|
|
1510
|
+
if (axios5.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1542
1511
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1543
1512
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1544
1513
|
name: this.indexName
|
|
@@ -1759,7 +1728,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1759
1728
|
await this.http.post("/v1/batch/objects", payload);
|
|
1760
1729
|
}
|
|
1761
1730
|
async query(vector, topK, namespace, _filter) {
|
|
1762
|
-
var
|
|
1731
|
+
var _a2, _b;
|
|
1763
1732
|
const queryText = _filter == null ? void 0 : _filter.queryText;
|
|
1764
1733
|
const sanitizedFilter = this.sanitizeFilter(_filter);
|
|
1765
1734
|
const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
|
|
@@ -1785,7 +1754,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1785
1754
|
`
|
|
1786
1755
|
};
|
|
1787
1756
|
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1788
|
-
const results = ((_b = (
|
|
1757
|
+
const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1789
1758
|
return results.map((res) => ({
|
|
1790
1759
|
id: res["_additional"].id,
|
|
1791
1760
|
score: 1 - res["_additional"].distance,
|
|
@@ -1838,10 +1807,10 @@ var init_WeaviateProvider = __esm({
|
|
|
1838
1807
|
return `{ operator: And, operands: [${operands.join(", ")}] }`;
|
|
1839
1808
|
}
|
|
1840
1809
|
weaviateOperand(key, value) {
|
|
1841
|
-
const
|
|
1842
|
-
if (typeof value === "number") return `{ ${
|
|
1843
|
-
if (typeof value === "boolean") return `{ ${
|
|
1844
|
-
return `{ ${
|
|
1810
|
+
const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
|
|
1811
|
+
if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
|
|
1812
|
+
if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
|
|
1813
|
+
return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
|
|
1845
1814
|
}
|
|
1846
1815
|
};
|
|
1847
1816
|
}
|
|
@@ -1868,21 +1837,21 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1868
1837
|
}
|
|
1869
1838
|
}
|
|
1870
1839
|
async initialize() {
|
|
1871
|
-
var
|
|
1840
|
+
var _a2;
|
|
1872
1841
|
this.http = axios8.create({
|
|
1873
1842
|
baseURL: this.opts.baseUrl,
|
|
1874
1843
|
headers: __spreadValues({
|
|
1875
1844
|
"Content-Type": "application/json"
|
|
1876
1845
|
}, this.opts.headers),
|
|
1877
|
-
timeout: (
|
|
1846
|
+
timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
|
|
1878
1847
|
});
|
|
1879
1848
|
if (!await this.ping()) {
|
|
1880
1849
|
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1881
1850
|
}
|
|
1882
1851
|
}
|
|
1883
1852
|
async upsert(doc, namespace) {
|
|
1884
|
-
var
|
|
1885
|
-
const endpoint = (
|
|
1853
|
+
var _a2, _b, _c;
|
|
1854
|
+
const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
|
|
1886
1855
|
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1887
1856
|
id: "{{id}}",
|
|
1888
1857
|
vector: "{{vector}}",
|
|
@@ -1915,8 +1884,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1915
1884
|
}
|
|
1916
1885
|
}
|
|
1917
1886
|
async query(vector, topK, namespace, filter) {
|
|
1918
|
-
var
|
|
1919
|
-
const endpoint = (
|
|
1887
|
+
var _a2, _b;
|
|
1888
|
+
const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
|
|
1920
1889
|
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1921
1890
|
vector: "{{vector}}",
|
|
1922
1891
|
limit: "{{topK}}",
|
|
@@ -1942,12 +1911,12 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1942
1911
|
);
|
|
1943
1912
|
}
|
|
1944
1913
|
return results.map((item) => {
|
|
1945
|
-
var
|
|
1914
|
+
var _a3, _b2, _c, _d, _e, _f, _g2;
|
|
1946
1915
|
return {
|
|
1947
|
-
id: item[(
|
|
1916
|
+
id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
|
|
1948
1917
|
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1949
1918
|
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1950
|
-
metadata: (
|
|
1919
|
+
metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
|
|
1951
1920
|
};
|
|
1952
1921
|
});
|
|
1953
1922
|
} catch (error) {
|
|
@@ -1957,8 +1926,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1957
1926
|
}
|
|
1958
1927
|
}
|
|
1959
1928
|
async delete(id, namespace) {
|
|
1960
|
-
var
|
|
1961
|
-
const endpoint = (
|
|
1929
|
+
var _a2, _b;
|
|
1930
|
+
const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
|
|
1962
1931
|
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1963
1932
|
id: "{{id}}",
|
|
1964
1933
|
namespace: "{{namespace}}"
|
|
@@ -1976,8 +1945,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1976
1945
|
}
|
|
1977
1946
|
}
|
|
1978
1947
|
async deleteNamespace(namespace) {
|
|
1979
|
-
var
|
|
1980
|
-
const endpoint = (
|
|
1948
|
+
var _a2;
|
|
1949
|
+
const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
|
|
1981
1950
|
try {
|
|
1982
1951
|
await this.http.post(endpoint, { namespace });
|
|
1983
1952
|
} catch (error) {
|
|
@@ -1987,9 +1956,9 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1987
1956
|
}
|
|
1988
1957
|
}
|
|
1989
1958
|
async ping() {
|
|
1990
|
-
var
|
|
1959
|
+
var _a2;
|
|
1991
1960
|
try {
|
|
1992
|
-
const endpoint = (
|
|
1961
|
+
const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
|
|
1993
1962
|
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
1994
1963
|
return response.status >= 200 && response.status < 300;
|
|
1995
1964
|
} catch (e) {
|
|
@@ -2100,6 +2069,8 @@ var LLM_PROVIDERS = [
|
|
|
2100
2069
|
"anthropic",
|
|
2101
2070
|
"ollama",
|
|
2102
2071
|
"gemini",
|
|
2072
|
+
"groq",
|
|
2073
|
+
"qwen",
|
|
2103
2074
|
"rest",
|
|
2104
2075
|
"universal_rest",
|
|
2105
2076
|
"custom"
|
|
@@ -2108,6 +2079,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2108
2079
|
"openai",
|
|
2109
2080
|
"ollama",
|
|
2110
2081
|
"gemini",
|
|
2082
|
+
"qwen",
|
|
2111
2083
|
"rest",
|
|
2112
2084
|
"universal_rest",
|
|
2113
2085
|
"custom"
|
|
@@ -2116,6 +2088,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2116
2088
|
"openai",
|
|
2117
2089
|
"ollama",
|
|
2118
2090
|
"gemini",
|
|
2091
|
+
"qwen",
|
|
2119
2092
|
"rest",
|
|
2120
2093
|
"universal_rest"
|
|
2121
2094
|
];
|
|
@@ -2123,8 +2096,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2123
2096
|
|
|
2124
2097
|
// src/config/serverConfig.ts
|
|
2125
2098
|
function readString(env, name) {
|
|
2126
|
-
var
|
|
2127
|
-
const value = (
|
|
2099
|
+
var _a2;
|
|
2100
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2128
2101
|
return value ? value : void 0;
|
|
2129
2102
|
}
|
|
2130
2103
|
function readNumber(env, name, fallback) {
|
|
@@ -2137,8 +2110,8 @@ function readNumber(env, name, fallback) {
|
|
|
2137
2110
|
return parsed;
|
|
2138
2111
|
}
|
|
2139
2112
|
function readEnum(env, name, fallback, allowed) {
|
|
2140
|
-
var
|
|
2141
|
-
const value = (
|
|
2113
|
+
var _a2;
|
|
2114
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2142
2115
|
if (allowed.includes(value)) {
|
|
2143
2116
|
return value;
|
|
2144
2117
|
}
|
|
@@ -2148,15 +2121,15 @@ function getRagConfig(baseConfig, env = process.env) {
|
|
|
2148
2121
|
return getEnvConfig(env, baseConfig);
|
|
2149
2122
|
}
|
|
2150
2123
|
function getEnvConfig(env = process.env, base) {
|
|
2151
|
-
var
|
|
2152
|
-
const projectId = (_c = (_b = (
|
|
2124
|
+
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;
|
|
2125
|
+
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__";
|
|
2153
2126
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2154
2127
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2155
2128
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2156
2129
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2157
2130
|
const vectorDbOptions = {};
|
|
2158
2131
|
if (vectorProvider === "pinecone") {
|
|
2159
|
-
vectorDbOptions.apiKey = (
|
|
2132
|
+
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 : "";
|
|
2160
2133
|
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;
|
|
2161
2134
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2162
2135
|
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 : "";
|
|
@@ -2218,17 +2191,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2218
2191
|
rest: "default",
|
|
2219
2192
|
custom: "default"
|
|
2220
2193
|
};
|
|
2221
|
-
return __spreadValues({
|
|
2194
|
+
return __spreadProps(__spreadValues({
|
|
2222
2195
|
projectId,
|
|
2196
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2223
2197
|
vectorDb: {
|
|
2224
2198
|
provider: vectorProvider,
|
|
2225
|
-
indexName: (
|
|
2199
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2226
2200
|
options: vectorDbOptions
|
|
2227
2201
|
},
|
|
2228
2202
|
llm: {
|
|
2229
2203
|
provider: llmProvider,
|
|
2230
|
-
model: (
|
|
2231
|
-
apiKey: (
|
|
2204
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2205
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2232
2206
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2233
2207
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2234
2208
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2241,7 +2215,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2241
2215
|
},
|
|
2242
2216
|
embedding: {
|
|
2243
2217
|
provider: embeddingProvider,
|
|
2244
|
-
model: (
|
|
2218
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2245
2219
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2246
2220
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2247
2221
|
dimensions: embeddingDimensions,
|
|
@@ -2252,30 +2226,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2252
2226
|
}
|
|
2253
2227
|
},
|
|
2254
2228
|
ui: {
|
|
2255
|
-
title: (
|
|
2256
|
-
subtitle: (
|
|
2257
|
-
primaryColor: (
|
|
2258
|
-
accentColor: (
|
|
2259
|
-
logoUrl: (
|
|
2260
|
-
placeholder: (
|
|
2261
|
-
showSources: ((
|
|
2262
|
-
welcomeMessage: (
|
|
2263
|
-
visualStyle: (
|
|
2264
|
-
borderRadius: (
|
|
2265
|
-
allowUpload: ((
|
|
2229
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2230
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2231
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2232
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2233
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2234
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2235
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2236
|
+
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.",
|
|
2237
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2238
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2239
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2266
2240
|
},
|
|
2267
2241
|
rag: {
|
|
2268
2242
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2269
2243
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2270
2244
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2271
2245
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2272
|
-
filterableFields: (
|
|
2246
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2273
2247
|
// Query pipeline toggles — read from .env.local
|
|
2274
2248
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2275
2249
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2276
2250
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2277
|
-
architecture: (
|
|
2278
|
-
chunkingStrategy: (
|
|
2251
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2252
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2279
2253
|
uiMapping: (() => {
|
|
2280
2254
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2281
2255
|
if (!raw) return void 0;
|
|
@@ -2285,6 +2259,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2285
2259
|
return void 0;
|
|
2286
2260
|
}
|
|
2287
2261
|
})()
|
|
2262
|
+
},
|
|
2263
|
+
telemetry: {
|
|
2264
|
+
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,
|
|
2265
|
+
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"
|
|
2288
2266
|
}
|
|
2289
2267
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2290
2268
|
graphDb: {
|
|
@@ -2295,49 +2273,21 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2295
2273
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2296
2274
|
}
|
|
2297
2275
|
}
|
|
2298
|
-
} : {})
|
|
2276
|
+
} : {}), {
|
|
2277
|
+
mcpServers: (() => {
|
|
2278
|
+
var _a3;
|
|
2279
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2280
|
+
if (!raw) return void 0;
|
|
2281
|
+
try {
|
|
2282
|
+
return JSON.parse(raw);
|
|
2283
|
+
} catch (e) {
|
|
2284
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2285
|
+
return void 0;
|
|
2286
|
+
}
|
|
2287
|
+
})()
|
|
2288
|
+
});
|
|
2299
2289
|
}
|
|
2300
2290
|
|
|
2301
|
-
// src/exceptions/index.ts
|
|
2302
|
-
var RetrivoraError = class extends Error {
|
|
2303
|
-
constructor(message, code, details) {
|
|
2304
|
-
super(message);
|
|
2305
|
-
this.name = new.target.name;
|
|
2306
|
-
this.code = code;
|
|
2307
|
-
this.details = details;
|
|
2308
|
-
}
|
|
2309
|
-
};
|
|
2310
|
-
var ProviderNotFoundException = class extends RetrivoraError {
|
|
2311
|
-
constructor(providerType, provider, details) {
|
|
2312
|
-
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
2313
|
-
}
|
|
2314
|
-
};
|
|
2315
|
-
var EmbeddingFailedException = class extends RetrivoraError {
|
|
2316
|
-
constructor(message = "Embedding generation failed", details) {
|
|
2317
|
-
super(message, "EMBEDDING_FAILED", details);
|
|
2318
|
-
}
|
|
2319
|
-
};
|
|
2320
|
-
var RetrievalException = class extends RetrivoraError {
|
|
2321
|
-
constructor(message = "Retrieval failed", details) {
|
|
2322
|
-
super(message, "RETRIEVAL_FAILED", details);
|
|
2323
|
-
}
|
|
2324
|
-
};
|
|
2325
|
-
var RateLimitException = class extends RetrivoraError {
|
|
2326
|
-
constructor(message = "Provider rate limit exceeded", details) {
|
|
2327
|
-
super(message, "RATE_LIMITED", details);
|
|
2328
|
-
}
|
|
2329
|
-
};
|
|
2330
|
-
var ConfigurationException = class extends RetrivoraError {
|
|
2331
|
-
constructor(message, details) {
|
|
2332
|
-
super(message, "CONFIGURATION_ERROR", details);
|
|
2333
|
-
}
|
|
2334
|
-
};
|
|
2335
|
-
var AuthenticationException = class extends RetrivoraError {
|
|
2336
|
-
constructor(message = "Provider authentication failed", details) {
|
|
2337
|
-
super(message, "AUTHENTICATION_ERROR", details);
|
|
2338
|
-
}
|
|
2339
|
-
};
|
|
2340
|
-
|
|
2341
2291
|
// src/core/ConfigResolver.ts
|
|
2342
2292
|
var ConfigResolver = class {
|
|
2343
2293
|
/**
|
|
@@ -2361,7 +2311,8 @@ var ConfigResolver = class {
|
|
|
2361
2311
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2362
2312
|
}) : envConfig.embedding,
|
|
2363
2313
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2364
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2314
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2315
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2365
2316
|
});
|
|
2366
2317
|
}
|
|
2367
2318
|
/**
|
|
@@ -2370,10 +2321,10 @@ var ConfigResolver = class {
|
|
|
2370
2321
|
* fallback behavior.
|
|
2371
2322
|
*/
|
|
2372
2323
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2373
|
-
var
|
|
2324
|
+
var _a2;
|
|
2374
2325
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2375
2326
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2376
|
-
vectorDb: (
|
|
2327
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2377
2328
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2378
2329
|
});
|
|
2379
2330
|
return this.resolve(normalized, env);
|
|
@@ -2383,21 +2334,21 @@ var ConfigResolver = class {
|
|
|
2383
2334
|
*/
|
|
2384
2335
|
static validate(config) {
|
|
2385
2336
|
if (!config.projectId) {
|
|
2386
|
-
throw new
|
|
2337
|
+
throw new Error("[ConfigResolver] projectId is required");
|
|
2387
2338
|
}
|
|
2388
2339
|
if (!config.vectorDb.provider) {
|
|
2389
|
-
throw new
|
|
2340
|
+
throw new Error("[ConfigResolver] vectorDb.provider is required");
|
|
2390
2341
|
}
|
|
2391
2342
|
if (!config.llm.provider) {
|
|
2392
|
-
throw new
|
|
2343
|
+
throw new Error("[ConfigResolver] llm.provider is required");
|
|
2393
2344
|
}
|
|
2394
2345
|
}
|
|
2395
2346
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2396
|
-
var
|
|
2347
|
+
var _a2, _b, _c, _d, _e;
|
|
2397
2348
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2398
2349
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2399
2350
|
if (retrieval) {
|
|
2400
|
-
normalized.topK = (
|
|
2351
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2401
2352
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2402
2353
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2403
2354
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
@@ -2479,8 +2430,8 @@ var OpenAIProvider = class {
|
|
|
2479
2430
|
const apiKey = config.apiKey;
|
|
2480
2431
|
const modelName = config.model;
|
|
2481
2432
|
try {
|
|
2482
|
-
const
|
|
2483
|
-
const client = new
|
|
2433
|
+
const OpenAI4 = await import("openai");
|
|
2434
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2484
2435
|
const models = await client.models.list();
|
|
2485
2436
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2486
2437
|
return {
|
|
@@ -2501,8 +2452,8 @@ var OpenAIProvider = class {
|
|
|
2501
2452
|
};
|
|
2502
2453
|
}
|
|
2503
2454
|
async chat(messages, context, options) {
|
|
2504
|
-
var
|
|
2505
|
-
const basePrompt = (_b = (
|
|
2455
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2456
|
+
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.";
|
|
2506
2457
|
const systemMessage = {
|
|
2507
2458
|
role: "system",
|
|
2508
2459
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2521,12 +2472,12 @@ var OpenAIProvider = class {
|
|
|
2521
2472
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2522
2473
|
stop: options == null ? void 0 : options.stop
|
|
2523
2474
|
});
|
|
2524
|
-
return (_i = (_h = (
|
|
2475
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2525
2476
|
}
|
|
2526
2477
|
chatStream(messages, context, options) {
|
|
2527
2478
|
return __asyncGenerator(this, null, function* () {
|
|
2528
|
-
var
|
|
2529
|
-
const basePrompt = (_b = (
|
|
2479
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2480
|
+
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.";
|
|
2530
2481
|
const systemMessage = {
|
|
2531
2482
|
role: "system",
|
|
2532
2483
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2552,7 +2503,7 @@ var OpenAIProvider = class {
|
|
|
2552
2503
|
try {
|
|
2553
2504
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2554
2505
|
const chunk = temp.value;
|
|
2555
|
-
const content = ((_h = (
|
|
2506
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2556
2507
|
if (content) yield content;
|
|
2557
2508
|
}
|
|
2558
2509
|
} catch (temp) {
|
|
@@ -2572,8 +2523,8 @@ var OpenAIProvider = class {
|
|
|
2572
2523
|
return results[0];
|
|
2573
2524
|
}
|
|
2574
2525
|
async batchEmbed(texts, options) {
|
|
2575
|
-
var
|
|
2576
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2526
|
+
var _a2, _b, _c, _d, _e;
|
|
2527
|
+
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";
|
|
2577
2528
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2578
2529
|
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI({ apiKey }) : this.client;
|
|
2579
2530
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2650,8 +2601,8 @@ var AnthropicProvider = class {
|
|
|
2650
2601
|
};
|
|
2651
2602
|
}
|
|
2652
2603
|
async chat(messages, context, options) {
|
|
2653
|
-
var
|
|
2654
|
-
const basePrompt = (_b = (
|
|
2604
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2605
|
+
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.";
|
|
2655
2606
|
const system = buildSystemContent(basePrompt, context);
|
|
2656
2607
|
const anthropicMessages = messages.map((m) => ({
|
|
2657
2608
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2662,7 +2613,7 @@ var AnthropicProvider = class {
|
|
|
2662
2613
|
const extraParams = {};
|
|
2663
2614
|
if (isThinkingEnabled && isClaude37) {
|
|
2664
2615
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2665
|
-
const maxTokens = (
|
|
2616
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2666
2617
|
const budget = Math.min(
|
|
2667
2618
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2668
2619
|
maxTokens - 1
|
|
@@ -2689,8 +2640,8 @@ var AnthropicProvider = class {
|
|
|
2689
2640
|
}
|
|
2690
2641
|
chatStream(messages, context, options) {
|
|
2691
2642
|
return __asyncGenerator(this, null, function* () {
|
|
2692
|
-
var
|
|
2693
|
-
const basePrompt = (_b = (
|
|
2643
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2644
|
+
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.";
|
|
2694
2645
|
const system = buildSystemContent(basePrompt, context);
|
|
2695
2646
|
const anthropicMessages = messages.map((m) => ({
|
|
2696
2647
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2701,7 +2652,7 @@ var AnthropicProvider = class {
|
|
|
2701
2652
|
const extraParams = {};
|
|
2702
2653
|
if (isThinkingEnabled && isClaude37) {
|
|
2703
2654
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2704
|
-
const maxTokens = (
|
|
2655
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2705
2656
|
const budget = Math.min(
|
|
2706
2657
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2707
2658
|
maxTokens - 1
|
|
@@ -2774,8 +2725,8 @@ var AnthropicProvider = class {
|
|
|
2774
2725
|
import axios from "axios";
|
|
2775
2726
|
var OllamaProvider = class {
|
|
2776
2727
|
constructor(llmConfig, embeddingConfig) {
|
|
2777
|
-
var
|
|
2778
|
-
const baseURL = (
|
|
2728
|
+
var _a2, _b;
|
|
2729
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2779
2730
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2780
2731
|
this.http = axios.create({ baseURL, timeout });
|
|
2781
2732
|
this.llmConfig = llmConfig;
|
|
@@ -2833,8 +2784,8 @@ var OllamaProvider = class {
|
|
|
2833
2784
|
};
|
|
2834
2785
|
}
|
|
2835
2786
|
async chat(messages, context, options) {
|
|
2836
|
-
var
|
|
2837
|
-
const basePrompt = (_b = (
|
|
2787
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2788
|
+
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.";
|
|
2838
2789
|
const system = buildSystemContent(basePrompt, context);
|
|
2839
2790
|
const { data } = await this.http.post("/api/chat", {
|
|
2840
2791
|
model: this.llmConfig.model,
|
|
@@ -2852,8 +2803,8 @@ var OllamaProvider = class {
|
|
|
2852
2803
|
}
|
|
2853
2804
|
chatStream(messages, context, options) {
|
|
2854
2805
|
return __asyncGenerator(this, null, function* () {
|
|
2855
|
-
var
|
|
2856
|
-
const basePrompt = (_b = (
|
|
2806
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2807
|
+
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.";
|
|
2857
2808
|
const system = buildSystemContent(basePrompt, context);
|
|
2858
2809
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2859
2810
|
model: this.llmConfig.model,
|
|
@@ -2882,7 +2833,7 @@ var OllamaProvider = class {
|
|
|
2882
2833
|
if (!line.trim()) continue;
|
|
2883
2834
|
try {
|
|
2884
2835
|
const json = JSON.parse(line);
|
|
2885
|
-
if ((
|
|
2836
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2886
2837
|
yield json.message.content;
|
|
2887
2838
|
}
|
|
2888
2839
|
if (json.done) return;
|
|
@@ -2911,10 +2862,10 @@ var OllamaProvider = class {
|
|
|
2911
2862
|
});
|
|
2912
2863
|
}
|
|
2913
2864
|
async embed(text, options) {
|
|
2914
|
-
var
|
|
2915
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2865
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2866
|
+
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";
|
|
2916
2867
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2917
|
-
const client = baseURL !== ((
|
|
2868
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? axios.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2918
2869
|
let prompt = text;
|
|
2919
2870
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2920
2871
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -3013,9 +2964,9 @@ var GeminiProvider = class {
|
|
|
3013
2964
|
static getHealthChecker() {
|
|
3014
2965
|
return {
|
|
3015
2966
|
async check(config) {
|
|
3016
|
-
var
|
|
2967
|
+
var _a2, _b;
|
|
3017
2968
|
const timestamp = Date.now();
|
|
3018
|
-
const apiKey = (_b = (
|
|
2969
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
3019
2970
|
const modelName = sanitizeModel(config.model);
|
|
3020
2971
|
try {
|
|
3021
2972
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -3045,16 +2996,16 @@ var GeminiProvider = class {
|
|
|
3045
2996
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
3046
2997
|
* API key differs from the LLM API key. */
|
|
3047
2998
|
get embeddingClient() {
|
|
3048
|
-
var
|
|
3049
|
-
if (((
|
|
2999
|
+
var _a2;
|
|
3000
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
3050
3001
|
return buildClient(this.embeddingConfig.apiKey);
|
|
3051
3002
|
}
|
|
3052
3003
|
return this.client;
|
|
3053
3004
|
}
|
|
3054
3005
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
3055
3006
|
resolveEmbeddingModel(optionsModel) {
|
|
3056
|
-
var
|
|
3057
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3007
|
+
var _a2, _b;
|
|
3008
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
3058
3009
|
}
|
|
3059
3010
|
/**
|
|
3060
3011
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3074,8 +3025,8 @@ var GeminiProvider = class {
|
|
|
3074
3025
|
// ILLMProvider — chat
|
|
3075
3026
|
// -------------------------------------------------------------------------
|
|
3076
3027
|
async chat(messages, context, options) {
|
|
3077
|
-
var
|
|
3078
|
-
const basePrompt = (_b = (
|
|
3028
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3029
|
+
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.";
|
|
3079
3030
|
const model = this.client.getGenerativeModel({
|
|
3080
3031
|
model: this.llmConfig.model,
|
|
3081
3032
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3092,8 +3043,8 @@ var GeminiProvider = class {
|
|
|
3092
3043
|
}
|
|
3093
3044
|
chatStream(messages, context, options) {
|
|
3094
3045
|
return __asyncGenerator(this, null, function* () {
|
|
3095
|
-
var
|
|
3096
|
-
const basePrompt = (_b = (
|
|
3046
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3047
|
+
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.";
|
|
3097
3048
|
const model = this.client.getGenerativeModel({
|
|
3098
3049
|
model: this.llmConfig.model,
|
|
3099
3050
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3128,11 +3079,11 @@ var GeminiProvider = class {
|
|
|
3128
3079
|
// ILLMProvider — embeddings
|
|
3129
3080
|
// -------------------------------------------------------------------------
|
|
3130
3081
|
async embed(text, options) {
|
|
3131
|
-
var
|
|
3082
|
+
var _a2, _b;
|
|
3132
3083
|
const content = applyPrefix(
|
|
3133
3084
|
text,
|
|
3134
3085
|
options == null ? void 0 : options.taskType,
|
|
3135
|
-
(
|
|
3086
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3136
3087
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3137
3088
|
);
|
|
3138
3089
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3149,7 +3100,7 @@ var GeminiProvider = class {
|
|
|
3149
3100
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3150
3101
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3151
3102
|
const requests = texts.map((text) => {
|
|
3152
|
-
var
|
|
3103
|
+
var _a2, _b;
|
|
3153
3104
|
return {
|
|
3154
3105
|
content: {
|
|
3155
3106
|
role: "user",
|
|
@@ -3157,7 +3108,7 @@ var GeminiProvider = class {
|
|
|
3157
3108
|
text: applyPrefix(
|
|
3158
3109
|
text,
|
|
3159
3110
|
options == null ? void 0 : options.taskType,
|
|
3160
|
-
(
|
|
3111
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3161
3112
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3162
3113
|
)
|
|
3163
3114
|
}]
|
|
@@ -3174,8 +3125,8 @@ var GeminiProvider = class {
|
|
|
3174
3125
|
throw err;
|
|
3175
3126
|
});
|
|
3176
3127
|
return response.embeddings.map((e) => {
|
|
3177
|
-
var
|
|
3178
|
-
return (
|
|
3128
|
+
var _a2;
|
|
3129
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3179
3130
|
});
|
|
3180
3131
|
}
|
|
3181
3132
|
// -------------------------------------------------------------------------
|
|
@@ -3195,163 +3146,482 @@ var GeminiProvider = class {
|
|
|
3195
3146
|
}
|
|
3196
3147
|
};
|
|
3197
3148
|
|
|
3198
|
-
// src/llm/providers/
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
var LLM_PROFILES = {
|
|
3211
|
-
"openai-compatible": OPENAI_BASE,
|
|
3212
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3213
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3214
|
-
}),
|
|
3215
|
-
"anthropic-claude": {
|
|
3216
|
-
chatPath: "/v1/messages",
|
|
3217
|
-
responseExtractPath: "content[0].text",
|
|
3218
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
3219
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3220
|
-
},
|
|
3221
|
-
"google-gemini": {
|
|
3222
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3223
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3224
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3225
|
-
},
|
|
3226
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3227
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3228
|
-
}),
|
|
3229
|
-
"ollama-standard": {
|
|
3230
|
-
chatPath: "/api/chat",
|
|
3231
|
-
embedPath: "/api/embeddings",
|
|
3232
|
-
responseExtractPath: "message.content",
|
|
3233
|
-
embedExtractPath: "embedding",
|
|
3234
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3235
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3149
|
+
// src/llm/providers/GroqProvider.ts
|
|
3150
|
+
import OpenAI2 from "openai";
|
|
3151
|
+
var GroqProvider = class {
|
|
3152
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3153
|
+
void embeddingConfig;
|
|
3154
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3155
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3156
|
+
this.client = new OpenAI2({
|
|
3157
|
+
apiKey,
|
|
3158
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3159
|
+
});
|
|
3160
|
+
this.llmConfig = llmConfig;
|
|
3236
3161
|
}
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
upsertPath: "/api/v1/collections/{{index}}/add",
|
|
3261
|
-
responseExtractPath: "matches",
|
|
3262
|
-
idPath: "id",
|
|
3263
|
-
scorePath: "distance",
|
|
3264
|
-
contentPath: "document",
|
|
3265
|
-
metadataPath: "metadata"
|
|
3266
|
-
},
|
|
3267
|
-
"qdrant": {
|
|
3268
|
-
queryPath: "/collections/{{index}}/points/search",
|
|
3269
|
-
upsertPath: "/collections/{{index}}/points",
|
|
3270
|
-
responseExtractPath: "result",
|
|
3271
|
-
idPath: "id",
|
|
3272
|
-
scorePath: "score",
|
|
3273
|
-
contentPath: "payload.content",
|
|
3274
|
-
metadataPath: "payload"
|
|
3162
|
+
static getValidator() {
|
|
3163
|
+
return {
|
|
3164
|
+
validate(config) {
|
|
3165
|
+
const errors = [];
|
|
3166
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3167
|
+
errors.push({
|
|
3168
|
+
field: "llm.apiKey",
|
|
3169
|
+
message: "Groq API key is required",
|
|
3170
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3171
|
+
severity: "error"
|
|
3172
|
+
});
|
|
3173
|
+
}
|
|
3174
|
+
if (!config.model) {
|
|
3175
|
+
errors.push({
|
|
3176
|
+
field: "llm.model",
|
|
3177
|
+
message: "Groq model name is required",
|
|
3178
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3179
|
+
severity: "error"
|
|
3180
|
+
});
|
|
3181
|
+
}
|
|
3182
|
+
return errors;
|
|
3183
|
+
}
|
|
3184
|
+
};
|
|
3275
3185
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3307
|
-
});
|
|
3186
|
+
static getHealthChecker() {
|
|
3187
|
+
return {
|
|
3188
|
+
async check(config) {
|
|
3189
|
+
const timestamp = Date.now();
|
|
3190
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3191
|
+
const modelName = config.model;
|
|
3192
|
+
try {
|
|
3193
|
+
const OpenAI4 = await import("openai");
|
|
3194
|
+
const client = new OpenAI4.default({
|
|
3195
|
+
apiKey,
|
|
3196
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3197
|
+
});
|
|
3198
|
+
const models = await client.models.list();
|
|
3199
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3200
|
+
return {
|
|
3201
|
+
healthy: true,
|
|
3202
|
+
provider: "groq",
|
|
3203
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3204
|
+
timestamp
|
|
3205
|
+
};
|
|
3206
|
+
} catch (error) {
|
|
3207
|
+
return {
|
|
3208
|
+
healthy: false,
|
|
3209
|
+
provider: "groq",
|
|
3210
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3211
|
+
timestamp
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
};
|
|
3308
3216
|
}
|
|
3309
|
-
async chat(messages, context) {
|
|
3310
|
-
var
|
|
3311
|
-
const
|
|
3217
|
+
async chat(messages, context, options) {
|
|
3218
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3219
|
+
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.";
|
|
3220
|
+
const systemMessage = {
|
|
3221
|
+
role: "system",
|
|
3222
|
+
content: buildSystemContent(basePrompt, context)
|
|
3223
|
+
};
|
|
3312
3224
|
const formattedMessages = [
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3225
|
+
systemMessage,
|
|
3226
|
+
...messages.map((m) => ({
|
|
3227
|
+
role: m.role,
|
|
3228
|
+
content: m.content
|
|
3229
|
+
}))
|
|
3318
3230
|
];
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
} else {
|
|
3328
|
-
payload = {
|
|
3329
|
-
model: this.model,
|
|
3330
|
-
messages: formattedMessages,
|
|
3331
|
-
max_tokens: this.maxTokens,
|
|
3332
|
-
temperature: this.temperature
|
|
3333
|
-
};
|
|
3334
|
-
}
|
|
3335
|
-
const { data } = await this.http.post(path, payload);
|
|
3336
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3337
|
-
const result = resolvePath(data, extractPath);
|
|
3338
|
-
if (result === void 0) {
|
|
3339
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3340
|
-
}
|
|
3341
|
-
return String(result);
|
|
3231
|
+
const completion = await this.client.chat.completions.create({
|
|
3232
|
+
model: this.llmConfig.model,
|
|
3233
|
+
messages: formattedMessages,
|
|
3234
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3235
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3236
|
+
stop: options == null ? void 0 : options.stop
|
|
3237
|
+
});
|
|
3238
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3342
3239
|
}
|
|
3343
|
-
|
|
3344
|
-
* Streaming chat using native fetch + ReadableStream.
|
|
3345
|
-
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3346
|
-
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3347
|
-
*/
|
|
3348
|
-
chatStream(messages, context) {
|
|
3240
|
+
chatStream(messages, context, options) {
|
|
3349
3241
|
return __asyncGenerator(this, null, function* () {
|
|
3350
|
-
var
|
|
3351
|
-
const
|
|
3352
|
-
const
|
|
3353
|
-
|
|
3354
|
-
|
|
3242
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3243
|
+
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.";
|
|
3244
|
+
const systemMessage = {
|
|
3245
|
+
role: "system",
|
|
3246
|
+
content: buildSystemContent(basePrompt, context)
|
|
3247
|
+
};
|
|
3248
|
+
const formattedMessages = [
|
|
3249
|
+
systemMessage,
|
|
3250
|
+
...messages.map((m) => ({
|
|
3251
|
+
role: m.role,
|
|
3252
|
+
content: m.content
|
|
3253
|
+
}))
|
|
3254
|
+
];
|
|
3255
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3256
|
+
model: this.llmConfig.model,
|
|
3257
|
+
messages: formattedMessages,
|
|
3258
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3259
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3260
|
+
stop: options == null ? void 0 : options.stop,
|
|
3261
|
+
stream: true
|
|
3262
|
+
}));
|
|
3263
|
+
if (!stream) {
|
|
3264
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3265
|
+
}
|
|
3266
|
+
try {
|
|
3267
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3268
|
+
const chunk = temp.value;
|
|
3269
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3270
|
+
if (content) yield content;
|
|
3271
|
+
}
|
|
3272
|
+
} catch (temp) {
|
|
3273
|
+
error = [temp];
|
|
3274
|
+
} finally {
|
|
3275
|
+
try {
|
|
3276
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3277
|
+
} finally {
|
|
3278
|
+
if (error)
|
|
3279
|
+
throw error[0];
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
});
|
|
3283
|
+
}
|
|
3284
|
+
async embed(text, options) {
|
|
3285
|
+
void text;
|
|
3286
|
+
void options;
|
|
3287
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3288
|
+
}
|
|
3289
|
+
async batchEmbed(texts, options) {
|
|
3290
|
+
void texts;
|
|
3291
|
+
void options;
|
|
3292
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3293
|
+
}
|
|
3294
|
+
async ping() {
|
|
3295
|
+
try {
|
|
3296
|
+
await this.client.models.list();
|
|
3297
|
+
return true;
|
|
3298
|
+
} catch (err) {
|
|
3299
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3300
|
+
return false;
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
};
|
|
3304
|
+
|
|
3305
|
+
// src/llm/providers/QwenProvider.ts
|
|
3306
|
+
import OpenAI3 from "openai";
|
|
3307
|
+
var QwenProvider = class {
|
|
3308
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3309
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3310
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3311
|
+
this.client = new OpenAI3({
|
|
3312
|
+
apiKey,
|
|
3313
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3314
|
+
});
|
|
3315
|
+
this.llmConfig = llmConfig;
|
|
3316
|
+
this.embeddingConfig = embeddingConfig;
|
|
3317
|
+
}
|
|
3318
|
+
static getValidator() {
|
|
3319
|
+
return {
|
|
3320
|
+
validate(config) {
|
|
3321
|
+
const errors = [];
|
|
3322
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3323
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3324
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3325
|
+
errors.push({
|
|
3326
|
+
field: `${prefix}.apiKey`,
|
|
3327
|
+
message: "Qwen API key is required",
|
|
3328
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3329
|
+
severity: "error"
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
if (!config.model) {
|
|
3333
|
+
errors.push({
|
|
3334
|
+
field: `${prefix}.model`,
|
|
3335
|
+
message: "Qwen model name is required",
|
|
3336
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3337
|
+
severity: "error"
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
return errors;
|
|
3341
|
+
}
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
static getHealthChecker() {
|
|
3345
|
+
return {
|
|
3346
|
+
async check(config) {
|
|
3347
|
+
const timestamp = Date.now();
|
|
3348
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3349
|
+
const modelName = config.model;
|
|
3350
|
+
try {
|
|
3351
|
+
const OpenAI4 = await import("openai");
|
|
3352
|
+
const client = new OpenAI4.default({
|
|
3353
|
+
apiKey,
|
|
3354
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3355
|
+
});
|
|
3356
|
+
const models = await client.models.list();
|
|
3357
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3358
|
+
return {
|
|
3359
|
+
healthy: true,
|
|
3360
|
+
provider: "qwen",
|
|
3361
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3362
|
+
timestamp
|
|
3363
|
+
};
|
|
3364
|
+
} catch (error) {
|
|
3365
|
+
return {
|
|
3366
|
+
healthy: false,
|
|
3367
|
+
provider: "qwen",
|
|
3368
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3369
|
+
timestamp
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
async chat(messages, context, options) {
|
|
3376
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3377
|
+
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.";
|
|
3378
|
+
const systemMessage = {
|
|
3379
|
+
role: "system",
|
|
3380
|
+
content: buildSystemContent(basePrompt, context)
|
|
3381
|
+
};
|
|
3382
|
+
const formattedMessages = [
|
|
3383
|
+
systemMessage,
|
|
3384
|
+
...messages.map((m) => ({
|
|
3385
|
+
role: m.role,
|
|
3386
|
+
content: m.content
|
|
3387
|
+
}))
|
|
3388
|
+
];
|
|
3389
|
+
const completion = await this.client.chat.completions.create({
|
|
3390
|
+
model: this.llmConfig.model,
|
|
3391
|
+
messages: formattedMessages,
|
|
3392
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3393
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3394
|
+
stop: options == null ? void 0 : options.stop
|
|
3395
|
+
});
|
|
3396
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3397
|
+
}
|
|
3398
|
+
chatStream(messages, context, options) {
|
|
3399
|
+
return __asyncGenerator(this, null, function* () {
|
|
3400
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3401
|
+
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.";
|
|
3402
|
+
const systemMessage = {
|
|
3403
|
+
role: "system",
|
|
3404
|
+
content: buildSystemContent(basePrompt, context)
|
|
3405
|
+
};
|
|
3406
|
+
const formattedMessages = [
|
|
3407
|
+
systemMessage,
|
|
3408
|
+
...messages.map((m) => ({
|
|
3409
|
+
role: m.role,
|
|
3410
|
+
content: m.content
|
|
3411
|
+
}))
|
|
3412
|
+
];
|
|
3413
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3414
|
+
model: this.llmConfig.model,
|
|
3415
|
+
messages: formattedMessages,
|
|
3416
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3417
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3418
|
+
stop: options == null ? void 0 : options.stop,
|
|
3419
|
+
stream: true
|
|
3420
|
+
}));
|
|
3421
|
+
if (!stream) {
|
|
3422
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3423
|
+
}
|
|
3424
|
+
try {
|
|
3425
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3426
|
+
const chunk = temp.value;
|
|
3427
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3428
|
+
if (content) yield content;
|
|
3429
|
+
}
|
|
3430
|
+
} catch (temp) {
|
|
3431
|
+
error = [temp];
|
|
3432
|
+
} finally {
|
|
3433
|
+
try {
|
|
3434
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3435
|
+
} finally {
|
|
3436
|
+
if (error)
|
|
3437
|
+
throw error[0];
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
});
|
|
3441
|
+
}
|
|
3442
|
+
async embed(text, options) {
|
|
3443
|
+
const results = await this.batchEmbed([text], options);
|
|
3444
|
+
return results[0];
|
|
3445
|
+
}
|
|
3446
|
+
async batchEmbed(texts, options) {
|
|
3447
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3448
|
+
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";
|
|
3449
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3450
|
+
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI3({
|
|
3451
|
+
apiKey,
|
|
3452
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3453
|
+
}) : this.client;
|
|
3454
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3455
|
+
return response.data.map((d) => d.embedding);
|
|
3456
|
+
}
|
|
3457
|
+
async ping() {
|
|
3458
|
+
try {
|
|
3459
|
+
await this.client.models.list();
|
|
3460
|
+
return true;
|
|
3461
|
+
} catch (err) {
|
|
3462
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3463
|
+
return false;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
};
|
|
3467
|
+
|
|
3468
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3469
|
+
init_templateUtils();
|
|
3470
|
+
import axios2 from "axios";
|
|
3471
|
+
|
|
3472
|
+
// src/config/UniversalProfiles.ts
|
|
3473
|
+
var OPENAI_BASE = {
|
|
3474
|
+
chatPath: "/chat/completions",
|
|
3475
|
+
embedPath: "/embeddings",
|
|
3476
|
+
responseExtractPath: "choices[0].message.content",
|
|
3477
|
+
embedExtractPath: "data[0].embedding",
|
|
3478
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3479
|
+
};
|
|
3480
|
+
var LLM_PROFILES = {
|
|
3481
|
+
"openai-compatible": OPENAI_BASE,
|
|
3482
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3483
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3484
|
+
}),
|
|
3485
|
+
"anthropic-claude": {
|
|
3486
|
+
chatPath: "/v1/messages",
|
|
3487
|
+
responseExtractPath: "content[0].text",
|
|
3488
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
3489
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3490
|
+
},
|
|
3491
|
+
"google-gemini": {
|
|
3492
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3493
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3494
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3495
|
+
},
|
|
3496
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3497
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3498
|
+
}),
|
|
3499
|
+
"ollama-standard": {
|
|
3500
|
+
chatPath: "/api/chat",
|
|
3501
|
+
embedPath: "/api/embeddings",
|
|
3502
|
+
responseExtractPath: "message.content",
|
|
3503
|
+
embedExtractPath: "embedding",
|
|
3504
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3505
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
var VECTOR_PROFILES = {
|
|
3509
|
+
"pinecone-rest": {
|
|
3510
|
+
queryPath: "/query",
|
|
3511
|
+
upsertPath: "/vectors/upsert",
|
|
3512
|
+
responseExtractPath: "matches",
|
|
3513
|
+
idPath: "id",
|
|
3514
|
+
scorePath: "score",
|
|
3515
|
+
contentPath: "metadata.content",
|
|
3516
|
+
metadataPath: "metadata",
|
|
3517
|
+
queryPayloadTemplate: '{"vector":{{vector}},"topK":{{topK}},"includeMetadata":true,"namespace":"{{namespace}}"}'
|
|
3518
|
+
},
|
|
3519
|
+
"mongodb-atlas": {
|
|
3520
|
+
queryPath: "/action/aggregate",
|
|
3521
|
+
responseExtractPath: "documents",
|
|
3522
|
+
idPath: "_id",
|
|
3523
|
+
scorePath: "score",
|
|
3524
|
+
contentPath: "content",
|
|
3525
|
+
metadataPath: "metadata",
|
|
3526
|
+
queryPayloadTemplate: '{"collection":"{{index}}","database":"ai_db","dataSource":"Cluster0","pipeline":[{"$vectorSearch":{"index":"vector_index","path":"embedding","queryVector":{{vector}},"numCandidates":100,"limit":{{topK}}}},{"$project":{"_id":1,"content":1,"metadata":1,"score":{"$meta":"vectorSearchScore"}}}]}'
|
|
3527
|
+
},
|
|
3528
|
+
"chromadb": {
|
|
3529
|
+
queryPath: "/api/v1/collections/{{index}}/query",
|
|
3530
|
+
upsertPath: "/api/v1/collections/{{index}}/add",
|
|
3531
|
+
responseExtractPath: "matches",
|
|
3532
|
+
idPath: "id",
|
|
3533
|
+
scorePath: "distance",
|
|
3534
|
+
contentPath: "document",
|
|
3535
|
+
metadataPath: "metadata"
|
|
3536
|
+
},
|
|
3537
|
+
"qdrant": {
|
|
3538
|
+
queryPath: "/collections/{{index}}/points/search",
|
|
3539
|
+
upsertPath: "/collections/{{index}}/points",
|
|
3540
|
+
responseExtractPath: "result",
|
|
3541
|
+
idPath: "id",
|
|
3542
|
+
scorePath: "score",
|
|
3543
|
+
contentPath: "payload.content",
|
|
3544
|
+
metadataPath: "payload"
|
|
3545
|
+
}
|
|
3546
|
+
};
|
|
3547
|
+
|
|
3548
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3549
|
+
var UniversalLLMAdapter = class {
|
|
3550
|
+
constructor(config) {
|
|
3551
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3552
|
+
this.model = config.model;
|
|
3553
|
+
const llmConfig = config;
|
|
3554
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3555
|
+
let profile = {};
|
|
3556
|
+
if (typeof options.profile === "string") {
|
|
3557
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
3558
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3559
|
+
profile = options.profile;
|
|
3560
|
+
}
|
|
3561
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3562
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3563
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3564
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3565
|
+
this.apiKey = config.apiKey;
|
|
3566
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3567
|
+
if (!this.baseUrl) {
|
|
3568
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3569
|
+
}
|
|
3570
|
+
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3571
|
+
"Content-Type": "application/json"
|
|
3572
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3573
|
+
this.http = axios2.create({
|
|
3574
|
+
baseURL: this.baseUrl,
|
|
3575
|
+
headers: this.resolvedHeaders,
|
|
3576
|
+
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3577
|
+
});
|
|
3578
|
+
}
|
|
3579
|
+
async chat(messages, context) {
|
|
3580
|
+
var _a2, _b;
|
|
3581
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3582
|
+
const formattedMessages = [
|
|
3583
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3584
|
+
|
|
3585
|
+
Context:
|
|
3586
|
+
${context != null ? context : "None"}` },
|
|
3587
|
+
...messages
|
|
3588
|
+
];
|
|
3589
|
+
let payload;
|
|
3590
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3591
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3592
|
+
model: this.model,
|
|
3593
|
+
messages: formattedMessages,
|
|
3594
|
+
maxTokens: this.maxTokens,
|
|
3595
|
+
temperature: this.temperature
|
|
3596
|
+
});
|
|
3597
|
+
} else {
|
|
3598
|
+
payload = {
|
|
3599
|
+
model: this.model,
|
|
3600
|
+
messages: formattedMessages,
|
|
3601
|
+
max_tokens: this.maxTokens,
|
|
3602
|
+
temperature: this.temperature
|
|
3603
|
+
};
|
|
3604
|
+
}
|
|
3605
|
+
const { data } = await this.http.post(path2, payload);
|
|
3606
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3607
|
+
const result = resolvePath(data, extractPath);
|
|
3608
|
+
if (result === void 0) {
|
|
3609
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3610
|
+
}
|
|
3611
|
+
return String(result);
|
|
3612
|
+
}
|
|
3613
|
+
/**
|
|
3614
|
+
* Streaming chat using native fetch + ReadableStream.
|
|
3615
|
+
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3616
|
+
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3617
|
+
*/
|
|
3618
|
+
chatStream(messages, context) {
|
|
3619
|
+
return __asyncGenerator(this, null, function* () {
|
|
3620
|
+
var _a2, _b, _c;
|
|
3621
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3622
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3623
|
+
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3624
|
+
const formattedMessages = [
|
|
3355
3625
|
{ role: "system", content: `${this.systemPrompt}
|
|
3356
3626
|
|
|
3357
3627
|
Context:
|
|
@@ -3427,8 +3697,8 @@ ${context != null ? context : "None"}` },
|
|
|
3427
3697
|
});
|
|
3428
3698
|
}
|
|
3429
3699
|
async embed(text) {
|
|
3430
|
-
var
|
|
3431
|
-
const
|
|
3700
|
+
var _a2, _b;
|
|
3701
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3432
3702
|
let payload;
|
|
3433
3703
|
if (this.opts.embedPayloadTemplate) {
|
|
3434
3704
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3441,7 +3711,7 @@ ${context != null ? context : "None"}` },
|
|
|
3441
3711
|
input: text
|
|
3442
3712
|
};
|
|
3443
3713
|
}
|
|
3444
|
-
const { data } = await this.http.post(
|
|
3714
|
+
const { data } = await this.http.post(path2, payload);
|
|
3445
3715
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3446
3716
|
const vector = resolvePath(data, extractPath);
|
|
3447
3717
|
if (!Array.isArray(vector)) {
|
|
@@ -3469,6 +3739,78 @@ ${context != null ? context : "None"}` },
|
|
|
3469
3739
|
}
|
|
3470
3740
|
};
|
|
3471
3741
|
|
|
3742
|
+
// src/exceptions/index.ts
|
|
3743
|
+
var RetrivoraError = class extends Error {
|
|
3744
|
+
constructor(message, code, details) {
|
|
3745
|
+
super(message);
|
|
3746
|
+
this.name = new.target.name;
|
|
3747
|
+
this.code = code;
|
|
3748
|
+
this.details = details;
|
|
3749
|
+
}
|
|
3750
|
+
};
|
|
3751
|
+
var ProviderNotFoundException = class extends RetrivoraError {
|
|
3752
|
+
constructor(providerType, provider, details) {
|
|
3753
|
+
super(`Unsupported ${providerType} provider: ${provider}`, "PROVIDER_NOT_FOUND", details);
|
|
3754
|
+
}
|
|
3755
|
+
};
|
|
3756
|
+
var EmbeddingFailedException = class extends RetrivoraError {
|
|
3757
|
+
constructor(message = "Embedding generation failed", details) {
|
|
3758
|
+
super(message, "EMBEDDING_FAILED", details);
|
|
3759
|
+
}
|
|
3760
|
+
};
|
|
3761
|
+
var RetrievalException = class extends RetrivoraError {
|
|
3762
|
+
constructor(message = "Retrieval failed", details) {
|
|
3763
|
+
super(message, "RETRIEVAL_FAILED", details);
|
|
3764
|
+
}
|
|
3765
|
+
};
|
|
3766
|
+
var RateLimitException = class extends RetrivoraError {
|
|
3767
|
+
constructor(message = "Provider rate limit exceeded", details) {
|
|
3768
|
+
super(message, "RATE_LIMITED", details);
|
|
3769
|
+
}
|
|
3770
|
+
};
|
|
3771
|
+
var ConfigurationException = class extends RetrivoraError {
|
|
3772
|
+
constructor(message, details) {
|
|
3773
|
+
super(message, "CONFIGURATION_ERROR", details);
|
|
3774
|
+
}
|
|
3775
|
+
};
|
|
3776
|
+
var AuthenticationException = class extends RetrivoraError {
|
|
3777
|
+
constructor(message = "Provider authentication failed", details) {
|
|
3778
|
+
super(message, "AUTHENTICATION_ERROR", details);
|
|
3779
|
+
}
|
|
3780
|
+
};
|
|
3781
|
+
function wrapError(err, defaultCode, defaultMessage) {
|
|
3782
|
+
var _a2;
|
|
3783
|
+
if (err instanceof RetrivoraError) {
|
|
3784
|
+
return err;
|
|
3785
|
+
}
|
|
3786
|
+
const error = err;
|
|
3787
|
+
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3788
|
+
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);
|
|
3789
|
+
const code = error == null ? void 0 : error.code;
|
|
3790
|
+
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3791
|
+
return new RateLimitException(message, err);
|
|
3792
|
+
}
|
|
3793
|
+
if (status === 401 || status === 403 || /unauthorized|auth|api[- ]?key/i.test(message) || code === "INVALID_API_KEY") {
|
|
3794
|
+
return new AuthenticationException(message, err);
|
|
3795
|
+
}
|
|
3796
|
+
switch (defaultCode) {
|
|
3797
|
+
case "PROVIDER_NOT_FOUND":
|
|
3798
|
+
return new ProviderNotFoundException("provider", message, err);
|
|
3799
|
+
case "EMBEDDING_FAILED":
|
|
3800
|
+
return new EmbeddingFailedException(message, err);
|
|
3801
|
+
case "RETRIEVAL_FAILED":
|
|
3802
|
+
return new RetrievalException(message, err);
|
|
3803
|
+
case "RATE_LIMITED":
|
|
3804
|
+
return new RateLimitException(message, err);
|
|
3805
|
+
case "CONFIGURATION_ERROR":
|
|
3806
|
+
return new ConfigurationException(message, err);
|
|
3807
|
+
case "AUTHENTICATION_ERROR":
|
|
3808
|
+
return new AuthenticationException(message, err);
|
|
3809
|
+
default:
|
|
3810
|
+
return new RetrivoraError(message, defaultCode, err);
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3813
|
+
|
|
3472
3814
|
// src/llm/LLMFactory.ts
|
|
3473
3815
|
var customProviders = /* @__PURE__ */ new Map();
|
|
3474
3816
|
var LLMFactory = class _LLMFactory {
|
|
@@ -3507,6 +3849,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3507
3849
|
"anthropic",
|
|
3508
3850
|
"ollama",
|
|
3509
3851
|
"gemini",
|
|
3852
|
+
"groq",
|
|
3853
|
+
"qwen",
|
|
3510
3854
|
"rest",
|
|
3511
3855
|
"universal_rest",
|
|
3512
3856
|
"custom",
|
|
@@ -3514,7 +3858,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3514
3858
|
];
|
|
3515
3859
|
}
|
|
3516
3860
|
static create(llmConfig, embeddingConfig) {
|
|
3517
|
-
var
|
|
3861
|
+
var _a2, _b, _c;
|
|
3518
3862
|
switch (llmConfig.provider) {
|
|
3519
3863
|
case "openai":
|
|
3520
3864
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3524,12 +3868,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3524
3868
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3525
3869
|
case "gemini":
|
|
3526
3870
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3871
|
+
case "groq":
|
|
3872
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3873
|
+
case "qwen":
|
|
3874
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3527
3875
|
case "rest":
|
|
3528
3876
|
case "universal_rest":
|
|
3529
3877
|
case "custom":
|
|
3530
3878
|
return new UniversalLLMAdapter(llmConfig);
|
|
3531
3879
|
default: {
|
|
3532
|
-
const providerName = String((
|
|
3880
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3533
3881
|
const customFactory = customProviders.get(providerName);
|
|
3534
3882
|
if (customFactory) {
|
|
3535
3883
|
return customFactory(llmConfig);
|
|
@@ -3538,9 +3886,12 @@ var LLMFactory = class _LLMFactory {
|
|
|
3538
3886
|
return new UniversalLLMAdapter(llmConfig);
|
|
3539
3887
|
}
|
|
3540
3888
|
throw new ProviderNotFoundException(
|
|
3541
|
-
"
|
|
3542
|
-
|
|
3543
|
-
|
|
3889
|
+
"llm",
|
|
3890
|
+
(_c = llmConfig.provider) != null ? _c : "undefined",
|
|
3891
|
+
{
|
|
3892
|
+
message: `Unknown provider "${llmConfig.provider}". Register a custom provider with LLMFactory.register().`,
|
|
3893
|
+
available: _LLMFactory.listProviders()
|
|
3894
|
+
}
|
|
3544
3895
|
);
|
|
3545
3896
|
}
|
|
3546
3897
|
}
|
|
@@ -3563,6 +3914,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3563
3914
|
return OllamaProvider;
|
|
3564
3915
|
case "gemini":
|
|
3565
3916
|
return GeminiProvider;
|
|
3917
|
+
case "groq":
|
|
3918
|
+
return GroqProvider;
|
|
3919
|
+
case "qwen":
|
|
3920
|
+
return QwenProvider;
|
|
3566
3921
|
case "rest":
|
|
3567
3922
|
case "universal_rest":
|
|
3568
3923
|
case "custom":
|
|
@@ -3624,7 +3979,7 @@ var ProviderRegistry = class {
|
|
|
3624
3979
|
return null;
|
|
3625
3980
|
}
|
|
3626
3981
|
static async loadVectorProviderClass(provider) {
|
|
3627
|
-
var
|
|
3982
|
+
var _a2;
|
|
3628
3983
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3629
3984
|
switch (provider) {
|
|
3630
3985
|
case "pinecone": {
|
|
@@ -3633,7 +3988,7 @@ var ProviderRegistry = class {
|
|
|
3633
3988
|
}
|
|
3634
3989
|
case "pgvector":
|
|
3635
3990
|
case "postgresql": {
|
|
3636
|
-
const postgresMode = ((
|
|
3991
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3637
3992
|
if (postgresMode === "single") {
|
|
3638
3993
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3639
3994
|
return PostgreSQLProvider2;
|
|
@@ -3853,6 +4208,125 @@ var ConfigValidator = class {
|
|
|
3853
4208
|
}
|
|
3854
4209
|
};
|
|
3855
4210
|
|
|
4211
|
+
// src/core/LicenseVerifier.ts
|
|
4212
|
+
import * as crypto2 from "crypto";
|
|
4213
|
+
var LicenseVerifier = class {
|
|
4214
|
+
/**
|
|
4215
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
4216
|
+
*
|
|
4217
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
4218
|
+
* @param currentProjectId - Project namespace ID.
|
|
4219
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
4220
|
+
*/
|
|
4221
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
4222
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4223
|
+
if (!licenseKey) {
|
|
4224
|
+
if (isProduction) {
|
|
4225
|
+
throw new ConfigurationException(
|
|
4226
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
4227
|
+
);
|
|
4228
|
+
}
|
|
4229
|
+
console.warn(
|
|
4230
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
4231
|
+
);
|
|
4232
|
+
return {
|
|
4233
|
+
projectId: currentProjectId,
|
|
4234
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
4235
|
+
// Valid for 24h
|
|
4236
|
+
tier: "hobby"
|
|
4237
|
+
};
|
|
4238
|
+
}
|
|
4239
|
+
try {
|
|
4240
|
+
const parts = licenseKey.split(".");
|
|
4241
|
+
if (parts.length !== 3) {
|
|
4242
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
4243
|
+
}
|
|
4244
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
4245
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
4246
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
4247
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
4248
|
+
const data = Buffer.from(dataToVerify);
|
|
4249
|
+
const isValid = crypto2.verify(
|
|
4250
|
+
"sha256",
|
|
4251
|
+
data,
|
|
4252
|
+
publicKey,
|
|
4253
|
+
signature
|
|
4254
|
+
);
|
|
4255
|
+
if (!isValid) {
|
|
4256
|
+
throw new Error("Signature verification failed.");
|
|
4257
|
+
}
|
|
4258
|
+
const payload = JSON.parse(
|
|
4259
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
4260
|
+
);
|
|
4261
|
+
if (!payload.projectId) {
|
|
4262
|
+
throw new Error('License payload is missing "projectId".');
|
|
4263
|
+
}
|
|
4264
|
+
if (payload.projectId !== currentProjectId) {
|
|
4265
|
+
throw new Error(
|
|
4266
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
4267
|
+
);
|
|
4268
|
+
}
|
|
4269
|
+
if (!payload.expiresAt) {
|
|
4270
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
4271
|
+
}
|
|
4272
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
4273
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
4274
|
+
throw new Error(
|
|
4275
|
+
`License key has expired. Expiration: ${new Date(
|
|
4276
|
+
payload.expiresAt * 1e3
|
|
4277
|
+
).toDateString()}`
|
|
4278
|
+
);
|
|
4279
|
+
}
|
|
4280
|
+
if (isProduction && provider) {
|
|
4281
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
4282
|
+
const normalizedProvider = provider.toLowerCase();
|
|
4283
|
+
if (tier === "hobby") {
|
|
4284
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
4285
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
4286
|
+
throw new Error(
|
|
4287
|
+
`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.`
|
|
4288
|
+
);
|
|
4289
|
+
}
|
|
4290
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
4291
|
+
const allowedPro = [
|
|
4292
|
+
"postgresql",
|
|
4293
|
+
"pgvector",
|
|
4294
|
+
"supabase",
|
|
4295
|
+
"pinecone",
|
|
4296
|
+
"qdrant",
|
|
4297
|
+
"mongodb",
|
|
4298
|
+
"milvus",
|
|
4299
|
+
"chroma",
|
|
4300
|
+
"chromadb"
|
|
4301
|
+
];
|
|
4302
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
4303
|
+
throw new Error(
|
|
4304
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
4305
|
+
);
|
|
4306
|
+
}
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
return payload;
|
|
4310
|
+
} catch (err) {
|
|
4311
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4312
|
+
throw new ConfigurationException(
|
|
4313
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
4314
|
+
);
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
};
|
|
4318
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
4319
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
4320
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
4321
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
4322
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
4323
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
4324
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
4325
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
4326
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
4327
|
+
MwIDAQAB
|
|
4328
|
+
-----END PUBLIC KEY-----`;
|
|
4329
|
+
|
|
3856
4330
|
// src/rag/DocumentChunker.ts
|
|
3857
4331
|
var DocumentChunker = class {
|
|
3858
4332
|
constructor(chunkSize = 1e3, chunkOverlap = 200, separators = ["\n# ", "\n## ", "\n### ", "\n#### ", "\n\n", "\n", " ", ""]) {
|
|
@@ -4082,11 +4556,11 @@ var LlamaIndexIngestor = class {
|
|
|
4082
4556
|
* than standard character-count splitting.
|
|
4083
4557
|
*/
|
|
4084
4558
|
async chunk(text, options = {}) {
|
|
4085
|
-
var
|
|
4559
|
+
var _a2, _b;
|
|
4086
4560
|
try {
|
|
4087
4561
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4088
4562
|
const splitter = new SentenceSplitter({
|
|
4089
|
-
chunkSize: (
|
|
4563
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4090
4564
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4091
4565
|
});
|
|
4092
4566
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4173,47 +4647,478 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
|
|
|
4173
4647
|
if (!finalSystemPrompt.includes("chart")) {
|
|
4174
4648
|
finalSystemPrompt += chartInstruction;
|
|
4175
4649
|
}
|
|
4176
|
-
this.agent = createAgent({
|
|
4177
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4178
|
-
model: chatModel,
|
|
4179
|
-
tools: [searchTool],
|
|
4180
|
-
systemPrompt: finalSystemPrompt
|
|
4650
|
+
this.agent = createAgent({
|
|
4651
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
4652
|
+
model: chatModel,
|
|
4653
|
+
tools: [searchTool],
|
|
4654
|
+
systemPrompt: finalSystemPrompt
|
|
4655
|
+
});
|
|
4656
|
+
} catch (error) {
|
|
4657
|
+
const isMissing = error instanceof Error && error.message.includes("Cannot find module");
|
|
4658
|
+
const hint = isMissing ? " Make sure 'langchain' and '@langchain/core' are installed:\n npm install langchain @langchain/core" : "";
|
|
4659
|
+
throw new Error(
|
|
4660
|
+
`[LangChainAgent] Failed to initialize.${hint}
|
|
4661
|
+
${error instanceof Error ? error.message : String(error)}`
|
|
4662
|
+
);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
/**
|
|
4666
|
+
* Run the agentic flow.
|
|
4667
|
+
*
|
|
4668
|
+
* LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
|
|
4669
|
+
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4670
|
+
*/
|
|
4671
|
+
async run(input, chatHistory = []) {
|
|
4672
|
+
var _a2, _b, _c;
|
|
4673
|
+
if (!this.agent) {
|
|
4674
|
+
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4675
|
+
}
|
|
4676
|
+
const { HumanMessage, AIMessage } = await import("@langchain/core/messages");
|
|
4677
|
+
const historyMessages = chatHistory.map(
|
|
4678
|
+
(m) => m.role === "user" ? new HumanMessage(m.content) : new AIMessage(m.content)
|
|
4679
|
+
);
|
|
4680
|
+
const response = await this.agent.invoke({
|
|
4681
|
+
messages: [...historyMessages, new HumanMessage(input)]
|
|
4682
|
+
});
|
|
4683
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4684
|
+
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4685
|
+
return lastMessage.content;
|
|
4686
|
+
}
|
|
4687
|
+
if (Array.isArray(lastMessage == null ? void 0 : lastMessage.content)) {
|
|
4688
|
+
return lastMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4689
|
+
}
|
|
4690
|
+
return String((_c = (_b = response == null ? void 0 : response.output) != null ? _b : response) != null ? _c : "");
|
|
4691
|
+
}
|
|
4692
|
+
};
|
|
4693
|
+
|
|
4694
|
+
// src/core/mcp.ts
|
|
4695
|
+
import { spawn } from "child_process";
|
|
4696
|
+
var MCPClient = class {
|
|
4697
|
+
constructor(config) {
|
|
4698
|
+
this.config = config;
|
|
4699
|
+
this.messageIdCounter = 0;
|
|
4700
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4701
|
+
this.stdioBuffer = "";
|
|
4702
|
+
this.initialized = false;
|
|
4703
|
+
}
|
|
4704
|
+
getNextMessageId() {
|
|
4705
|
+
return ++this.messageIdCounter;
|
|
4706
|
+
}
|
|
4707
|
+
/**
|
|
4708
|
+
* Connect and initialize the MCP server connection.
|
|
4709
|
+
*/
|
|
4710
|
+
async connect() {
|
|
4711
|
+
if (this.initialized) return;
|
|
4712
|
+
if (this.config.transport === "stdio") {
|
|
4713
|
+
await this.connectStdio();
|
|
4714
|
+
} else {
|
|
4715
|
+
await this.connectSSE();
|
|
4716
|
+
}
|
|
4717
|
+
try {
|
|
4718
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4719
|
+
protocolVersion: "2024-11-05",
|
|
4720
|
+
capabilities: {},
|
|
4721
|
+
clientInfo: {
|
|
4722
|
+
name: "retrivora-sdk",
|
|
4723
|
+
version: "1.0.0"
|
|
4724
|
+
}
|
|
4725
|
+
});
|
|
4726
|
+
await this.sendNotification("notifications/initialized");
|
|
4727
|
+
this.initialized = true;
|
|
4728
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4729
|
+
} catch (err) {
|
|
4730
|
+
this.disconnect();
|
|
4731
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
async connectStdio() {
|
|
4735
|
+
var _a2;
|
|
4736
|
+
const cmd = this.config.command;
|
|
4737
|
+
if (!cmd) {
|
|
4738
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4739
|
+
}
|
|
4740
|
+
const args = this.config.args || [];
|
|
4741
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4742
|
+
this.childProcess = spawn(cmd, args, { env, shell: true });
|
|
4743
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4744
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4745
|
+
}
|
|
4746
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4747
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4748
|
+
this.processStdioLines();
|
|
4749
|
+
});
|
|
4750
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4751
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4752
|
+
});
|
|
4753
|
+
this.childProcess.on("close", (code) => {
|
|
4754
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4755
|
+
this.disconnect();
|
|
4756
|
+
});
|
|
4757
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4758
|
+
}
|
|
4759
|
+
processStdioLines() {
|
|
4760
|
+
let newlineIndex;
|
|
4761
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4762
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4763
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4764
|
+
if (!line) continue;
|
|
4765
|
+
try {
|
|
4766
|
+
const payload = JSON.parse(line);
|
|
4767
|
+
if (payload.id !== void 0) {
|
|
4768
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4769
|
+
if (req) {
|
|
4770
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4771
|
+
if (payload.error) {
|
|
4772
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4773
|
+
} else {
|
|
4774
|
+
req.resolve(payload.result);
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
} catch (e) {
|
|
4779
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
async connectSSE() {
|
|
4784
|
+
if (!this.config.url) {
|
|
4785
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4786
|
+
}
|
|
4787
|
+
this.sseUrl = this.config.url;
|
|
4788
|
+
}
|
|
4789
|
+
async sendJsonRpc(method, params) {
|
|
4790
|
+
const id = this.getNextMessageId();
|
|
4791
|
+
const request = {
|
|
4792
|
+
jsonrpc: "2.0",
|
|
4793
|
+
id,
|
|
4794
|
+
method,
|
|
4795
|
+
params
|
|
4796
|
+
};
|
|
4797
|
+
if (this.config.transport === "stdio") {
|
|
4798
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4799
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4800
|
+
}
|
|
4801
|
+
return new Promise((resolve, reject) => {
|
|
4802
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4803
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4181
4804
|
});
|
|
4182
|
-
}
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4805
|
+
} else {
|
|
4806
|
+
if (!this.sseUrl) {
|
|
4807
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4808
|
+
}
|
|
4809
|
+
const response = await fetch(this.sseUrl, {
|
|
4810
|
+
method: "POST",
|
|
4811
|
+
headers: { "Content-Type": "application/json" },
|
|
4812
|
+
body: JSON.stringify(request)
|
|
4813
|
+
});
|
|
4814
|
+
if (!response.ok) {
|
|
4815
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4816
|
+
}
|
|
4817
|
+
const payload = await response.json();
|
|
4818
|
+
if (payload.error) {
|
|
4819
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4820
|
+
}
|
|
4821
|
+
return payload.result;
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
async sendNotification(method, params) {
|
|
4825
|
+
var _a2;
|
|
4826
|
+
const notification = {
|
|
4827
|
+
jsonrpc: "2.0",
|
|
4828
|
+
method,
|
|
4829
|
+
params
|
|
4830
|
+
};
|
|
4831
|
+
if (this.config.transport === "stdio") {
|
|
4832
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4833
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4834
|
+
}
|
|
4835
|
+
} else if (this.sseUrl) {
|
|
4836
|
+
await fetch(this.sseUrl, {
|
|
4837
|
+
method: "POST",
|
|
4838
|
+
headers: { "Content-Type": "application/json" },
|
|
4839
|
+
body: JSON.stringify(notification)
|
|
4840
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4189
4841
|
}
|
|
4190
4842
|
}
|
|
4191
4843
|
/**
|
|
4192
|
-
*
|
|
4193
|
-
*
|
|
4194
|
-
* LangChain v1.x: invoke takes `{ messages: [...] }` instead of `{ input, chat_history }`.
|
|
4195
|
-
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4844
|
+
* List all tools offered by the MCP server.
|
|
4196
4845
|
*/
|
|
4197
|
-
async
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4846
|
+
async listTools() {
|
|
4847
|
+
await this.connect();
|
|
4848
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4849
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* Execute a tool on the MCP server.
|
|
4853
|
+
*/
|
|
4854
|
+
async callTool(name, args = {}) {
|
|
4855
|
+
await this.connect();
|
|
4856
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4857
|
+
}
|
|
4858
|
+
disconnect() {
|
|
4859
|
+
this.initialized = false;
|
|
4860
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4861
|
+
this.pendingRequests.clear();
|
|
4862
|
+
if (this.childProcess) {
|
|
4863
|
+
try {
|
|
4864
|
+
this.childProcess.kill();
|
|
4865
|
+
} catch (e) {
|
|
4866
|
+
}
|
|
4867
|
+
this.childProcess = void 0;
|
|
4201
4868
|
}
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4869
|
+
}
|
|
4870
|
+
};
|
|
4871
|
+
var MCPRegistry = class {
|
|
4872
|
+
constructor(servers = []) {
|
|
4873
|
+
this.clients = [];
|
|
4874
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4875
|
+
}
|
|
4876
|
+
async getAllTools() {
|
|
4877
|
+
const list = [];
|
|
4878
|
+
await Promise.all(
|
|
4879
|
+
this.clients.map(async (client) => {
|
|
4880
|
+
try {
|
|
4881
|
+
const tools = await client.listTools();
|
|
4882
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4883
|
+
} catch (e) {
|
|
4884
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4885
|
+
}
|
|
4886
|
+
})
|
|
4205
4887
|
);
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4888
|
+
return list;
|
|
4889
|
+
}
|
|
4890
|
+
async callTool(toolName, args = {}) {
|
|
4891
|
+
for (const client of this.clients) {
|
|
4892
|
+
try {
|
|
4893
|
+
const tools = await client.listTools();
|
|
4894
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4895
|
+
return await client.callTool(toolName, args);
|
|
4896
|
+
}
|
|
4897
|
+
} catch (e) {
|
|
4898
|
+
}
|
|
4212
4899
|
}
|
|
4213
|
-
|
|
4214
|
-
|
|
4900
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4901
|
+
}
|
|
4902
|
+
disconnectAll() {
|
|
4903
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4904
|
+
}
|
|
4905
|
+
};
|
|
4906
|
+
|
|
4907
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4908
|
+
var MultiAgentCoordinator = class {
|
|
4909
|
+
constructor(options) {
|
|
4910
|
+
var _a2;
|
|
4911
|
+
this.llmProvider = options.llmProvider;
|
|
4912
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4913
|
+
this.documentSearch = options.documentSearch;
|
|
4914
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
4915
|
+
}
|
|
4916
|
+
/**
|
|
4917
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
4918
|
+
*/
|
|
4919
|
+
async run(question, history = []) {
|
|
4920
|
+
const generator = this.runStream(question, history);
|
|
4921
|
+
let finalReply = "";
|
|
4922
|
+
const sources = [];
|
|
4923
|
+
try {
|
|
4924
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4925
|
+
const chunk = temp.value;
|
|
4926
|
+
if (typeof chunk === "string") {
|
|
4927
|
+
finalReply += chunk;
|
|
4928
|
+
} else if (chunk && typeof chunk === "object") {
|
|
4929
|
+
if ("reply" in chunk && chunk.reply) {
|
|
4930
|
+
finalReply += chunk.reply;
|
|
4931
|
+
}
|
|
4932
|
+
if ("sources" in chunk && chunk.sources) {
|
|
4933
|
+
sources.push(...chunk.sources);
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
} catch (temp) {
|
|
4938
|
+
error = [temp];
|
|
4939
|
+
} finally {
|
|
4940
|
+
try {
|
|
4941
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4942
|
+
} finally {
|
|
4943
|
+
if (error)
|
|
4944
|
+
throw error[0];
|
|
4945
|
+
}
|
|
4215
4946
|
}
|
|
4216
|
-
return
|
|
4947
|
+
return {
|
|
4948
|
+
reply: finalReply,
|
|
4949
|
+
sources
|
|
4950
|
+
};
|
|
4951
|
+
}
|
|
4952
|
+
/**
|
|
4953
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
4954
|
+
*/
|
|
4955
|
+
runStream(_0) {
|
|
4956
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
4957
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
4958
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
4959
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
4960
|
+
|
|
4961
|
+
Available Tools:
|
|
4962
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
4963
|
+
|
|
4964
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
4965
|
+
${mcpTools.map((mt) => {
|
|
4966
|
+
var _a2;
|
|
4967
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
4968
|
+
}).join("\n")}
|
|
4969
|
+
|
|
4970
|
+
Tool Calling Protocol:
|
|
4971
|
+
If you need to call a tool, write:
|
|
4972
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
4973
|
+
And then STOP generating immediately.
|
|
4974
|
+
|
|
4975
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
4976
|
+
`;
|
|
4977
|
+
const supervisorHistory = [
|
|
4978
|
+
{ role: "system", content: systemPrompt },
|
|
4979
|
+
...history,
|
|
4980
|
+
{ role: "user", content: question }
|
|
4981
|
+
];
|
|
4982
|
+
let iteration = 0;
|
|
4983
|
+
const allSources = [];
|
|
4984
|
+
while (iteration < this.maxIterations) {
|
|
4985
|
+
iteration++;
|
|
4986
|
+
const context = "";
|
|
4987
|
+
let fullModelResponse = "";
|
|
4988
|
+
let textBuffer = "";
|
|
4989
|
+
let inThinking = false;
|
|
4990
|
+
let toolCallDetected = null;
|
|
4991
|
+
if (!this.llmProvider.chatStream) {
|
|
4992
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
4993
|
+
fullModelResponse = reply;
|
|
4994
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
4995
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
4996
|
+
let thinkingText = "";
|
|
4997
|
+
let answerText = reply;
|
|
4998
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
4999
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
5000
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
5001
|
+
yield { type: "thinking", text: thinkingText };
|
|
5002
|
+
}
|
|
5003
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5004
|
+
if (toolMatch) {
|
|
5005
|
+
const toolName = toolMatch[1];
|
|
5006
|
+
const toolArgsStr = toolMatch[2];
|
|
5007
|
+
try {
|
|
5008
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5009
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5010
|
+
} catch (e) {
|
|
5011
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5012
|
+
}
|
|
5013
|
+
} else {
|
|
5014
|
+
yield answerText;
|
|
5015
|
+
}
|
|
5016
|
+
} else {
|
|
5017
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
5018
|
+
try {
|
|
5019
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
5020
|
+
const chunk = temp.value;
|
|
5021
|
+
fullModelResponse += chunk;
|
|
5022
|
+
textBuffer += chunk;
|
|
5023
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
5024
|
+
inThinking = true;
|
|
5025
|
+
const idx = textBuffer.indexOf("<think>");
|
|
5026
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
5027
|
+
}
|
|
5028
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
5029
|
+
inThinking = false;
|
|
5030
|
+
const idx = textBuffer.indexOf("</think>");
|
|
5031
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
5032
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
5033
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
5034
|
+
}
|
|
5035
|
+
if (inThinking && textBuffer.length > 0) {
|
|
5036
|
+
yield { type: "thinking", text: textBuffer };
|
|
5037
|
+
textBuffer = "";
|
|
5038
|
+
}
|
|
5039
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
5040
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
5041
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
5042
|
+
if (precedingText.trim()) {
|
|
5043
|
+
yield precedingText;
|
|
5044
|
+
}
|
|
5045
|
+
textBuffer = textBuffer.slice(idx);
|
|
5046
|
+
}
|
|
5047
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
5048
|
+
yield textBuffer;
|
|
5049
|
+
textBuffer = "";
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
5052
|
+
} catch (temp) {
|
|
5053
|
+
error = [temp];
|
|
5054
|
+
} finally {
|
|
5055
|
+
try {
|
|
5056
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
5057
|
+
} finally {
|
|
5058
|
+
if (error)
|
|
5059
|
+
throw error[0];
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
if (textBuffer.trim()) {
|
|
5063
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
5064
|
+
if (toolMatch) {
|
|
5065
|
+
const toolName = toolMatch[1];
|
|
5066
|
+
const toolArgsStr = toolMatch[2];
|
|
5067
|
+
try {
|
|
5068
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
5069
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
5070
|
+
} catch (e) {
|
|
5071
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
5072
|
+
}
|
|
5073
|
+
} else {
|
|
5074
|
+
yield textBuffer;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
5079
|
+
if (toolCallDetected) {
|
|
5080
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
5081
|
+
yield {
|
|
5082
|
+
type: "thinking",
|
|
5083
|
+
text: `
|
|
5084
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
5085
|
+
`
|
|
5086
|
+
};
|
|
5087
|
+
let toolResultText = "";
|
|
5088
|
+
try {
|
|
5089
|
+
if (toolName === "document_search") {
|
|
5090
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
5091
|
+
toolResultText = `document_search returned:
|
|
5092
|
+
${searchRes.reply}
|
|
5093
|
+
|
|
5094
|
+
Sources count: ${searchRes.sources.length}`;
|
|
5095
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
5096
|
+
allSources.push(...searchRes.sources);
|
|
5097
|
+
yield { reply: "", sources: searchRes.sources };
|
|
5098
|
+
}
|
|
5099
|
+
} else {
|
|
5100
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
5101
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
5102
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
5103
|
+
}
|
|
5104
|
+
} catch (err) {
|
|
5105
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
5106
|
+
}
|
|
5107
|
+
supervisorHistory.push({
|
|
5108
|
+
role: "user",
|
|
5109
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
5110
|
+
${toolResultText}`
|
|
5111
|
+
});
|
|
5112
|
+
yield {
|
|
5113
|
+
type: "thinking",
|
|
5114
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
5115
|
+
`
|
|
5116
|
+
};
|
|
5117
|
+
} else {
|
|
5118
|
+
break;
|
|
5119
|
+
}
|
|
5120
|
+
}
|
|
5121
|
+
});
|
|
4217
5122
|
}
|
|
4218
5123
|
};
|
|
4219
5124
|
|
|
@@ -4543,7 +5448,7 @@ var QueryProcessor = class {
|
|
|
4543
5448
|
* @param validFields Optional list of known filterable fields to look for
|
|
4544
5449
|
*/
|
|
4545
5450
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4546
|
-
var
|
|
5451
|
+
var _a2, _b, _c, _d;
|
|
4547
5452
|
if (!question.trim()) return [];
|
|
4548
5453
|
const hints = /* @__PURE__ */ new Map();
|
|
4549
5454
|
const addHint = (value, field) => {
|
|
@@ -4623,7 +5528,7 @@ var QueryProcessor = class {
|
|
|
4623
5528
|
];
|
|
4624
5529
|
for (const p of universalPatterns) {
|
|
4625
5530
|
for (const match of question.matchAll(p.regex)) {
|
|
4626
|
-
const val = p.group ? (
|
|
5531
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4627
5532
|
if (!val) continue;
|
|
4628
5533
|
if (p.field) addHint(val, p.field);
|
|
4629
5534
|
else addHint(val);
|
|
@@ -4847,11 +5752,11 @@ var LLMRouter = class {
|
|
|
4847
5752
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4848
5753
|
*/
|
|
4849
5754
|
async initialize(prebuiltDefault) {
|
|
4850
|
-
var
|
|
5755
|
+
var _a2;
|
|
4851
5756
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4852
5757
|
this.models.set("default", defaultModel);
|
|
4853
5758
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4854
|
-
const providerFastDefault = (
|
|
5759
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4855
5760
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4856
5761
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4857
5762
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4870,8 +5775,8 @@ var LLMRouter = class {
|
|
|
4870
5775
|
* Falls back to 'default' if the requested role is not registered.
|
|
4871
5776
|
*/
|
|
4872
5777
|
get(role) {
|
|
4873
|
-
var
|
|
4874
|
-
const provider = (
|
|
5778
|
+
var _a2;
|
|
5779
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4875
5780
|
if (!provider) {
|
|
4876
5781
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4877
5782
|
}
|
|
@@ -4889,7 +5794,7 @@ var UITransformer = class _UITransformer {
|
|
|
4889
5794
|
* Prefer `analyzeAndDecide()` in production.
|
|
4890
5795
|
*/
|
|
4891
5796
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4892
|
-
var
|
|
5797
|
+
var _a2, _b, _c;
|
|
4893
5798
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4894
5799
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4895
5800
|
}
|
|
@@ -4909,7 +5814,7 @@ var UITransformer = class _UITransformer {
|
|
|
4909
5814
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4910
5815
|
}
|
|
4911
5816
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4912
|
-
return (
|
|
5817
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4913
5818
|
}
|
|
4914
5819
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4915
5820
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5234,11 +6139,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5234
6139
|
};
|
|
5235
6140
|
}
|
|
5236
6141
|
static transformToPieChart(data, profile, query = "") {
|
|
5237
|
-
var
|
|
6142
|
+
var _a2;
|
|
5238
6143
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5239
6144
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5240
|
-
var
|
|
5241
|
-
return String((
|
|
6145
|
+
var _a3;
|
|
6146
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5242
6147
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5243
6148
|
if (categories.length === 0) return null;
|
|
5244
6149
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5248,7 +6153,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5248
6153
|
});
|
|
5249
6154
|
return {
|
|
5250
6155
|
type: "pie_chart",
|
|
5251
|
-
title: `Distribution by ${(
|
|
6156
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5252
6157
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5253
6158
|
data: pieData
|
|
5254
6159
|
};
|
|
@@ -5258,8 +6163,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5258
6163
|
const valueField = profile.numericFields[0];
|
|
5259
6164
|
const buckets = /* @__PURE__ */ new Map();
|
|
5260
6165
|
profile.records.forEach((record) => {
|
|
5261
|
-
var
|
|
5262
|
-
const timestamp = String((
|
|
6166
|
+
var _a2, _b, _c;
|
|
6167
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5263
6168
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5264
6169
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5265
6170
|
});
|
|
@@ -5272,23 +6177,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5272
6177
|
};
|
|
5273
6178
|
}
|
|
5274
6179
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5275
|
-
var
|
|
6180
|
+
var _a2;
|
|
5276
6181
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5277
6182
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5278
6183
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5279
6184
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5280
6185
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5281
|
-
var
|
|
6186
|
+
var _a3, _b, _c, _d, _e;
|
|
5282
6187
|
const meta = item.metadata || {};
|
|
5283
6188
|
const label = String(
|
|
5284
|
-
(_c = (_b = (
|
|
6189
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5285
6190
|
);
|
|
5286
6191
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5287
6192
|
return { category: label, value: Number(value) };
|
|
5288
6193
|
});
|
|
5289
6194
|
return {
|
|
5290
6195
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5291
|
-
title: dimension ? `${(
|
|
6196
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5292
6197
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5293
6198
|
data: fallbackData
|
|
5294
6199
|
};
|
|
@@ -5323,11 +6228,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5323
6228
|
if (fields.length < 2) return null;
|
|
5324
6229
|
const [xField, yField] = fields;
|
|
5325
6230
|
const points = profile.records.map((record) => {
|
|
5326
|
-
var
|
|
6231
|
+
var _a2;
|
|
5327
6232
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5328
6233
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5329
6234
|
if (x === null || y === null) return null;
|
|
5330
|
-
return { x, y, label: String((
|
|
6235
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5331
6236
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5332
6237
|
if (points.length === 0) return null;
|
|
5333
6238
|
return {
|
|
@@ -5357,9 +6262,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5357
6262
|
static transformToRadarChart(data) {
|
|
5358
6263
|
const attributeMap = {};
|
|
5359
6264
|
data.forEach((item) => {
|
|
5360
|
-
var
|
|
6265
|
+
var _a2, _b, _c;
|
|
5361
6266
|
const meta = item.metadata || {};
|
|
5362
|
-
const seriesName = String((_c = (_b = (
|
|
6267
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5363
6268
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5364
6269
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5365
6270
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5441,22 +6346,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5441
6346
|
return null;
|
|
5442
6347
|
}
|
|
5443
6348
|
static normalizeTransformation(payload) {
|
|
5444
|
-
var
|
|
6349
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5445
6350
|
if (!payload || typeof payload !== "object") return null;
|
|
5446
6351
|
const p = payload;
|
|
5447
6352
|
const type = this.normalizeVisualizationType(
|
|
5448
|
-
String((_c = (_b = (
|
|
6353
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5449
6354
|
);
|
|
5450
6355
|
if (!type) return null;
|
|
5451
6356
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5452
6357
|
const description = p.description ? String(p.description) : void 0;
|
|
5453
|
-
const rawData = (_j = (_i = (_h = (
|
|
6358
|
+
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;
|
|
5454
6359
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5455
6360
|
const transformation = { type, title, description, data };
|
|
5456
6361
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5457
6362
|
}
|
|
5458
6363
|
static normalizeVisualizationType(type) {
|
|
5459
|
-
var
|
|
6364
|
+
var _a2;
|
|
5460
6365
|
const mapping = {
|
|
5461
6366
|
pie: "pie_chart",
|
|
5462
6367
|
pie_chart: "pie_chart",
|
|
@@ -5484,7 +6389,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5484
6389
|
product_carousel: "product_carousel",
|
|
5485
6390
|
carousel: "carousel"
|
|
5486
6391
|
};
|
|
5487
|
-
return (
|
|
6392
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5488
6393
|
}
|
|
5489
6394
|
static validateTransformation(t) {
|
|
5490
6395
|
const { type, data } = t;
|
|
@@ -5686,16 +6591,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5686
6591
|
return null;
|
|
5687
6592
|
}
|
|
5688
6593
|
static selectDimensionField(profile, query) {
|
|
5689
|
-
var
|
|
6594
|
+
var _a2, _b;
|
|
5690
6595
|
const productCategory = profile.categoricalFields.find(
|
|
5691
6596
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5692
6597
|
);
|
|
5693
6598
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5694
|
-
return (_b = (
|
|
6599
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5695
6600
|
}
|
|
5696
6601
|
static selectNumericField(profile, query) {
|
|
5697
|
-
var
|
|
5698
|
-
return (
|
|
6602
|
+
var _a2;
|
|
6603
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5699
6604
|
}
|
|
5700
6605
|
static rankFieldsByQuery(fields, query) {
|
|
5701
6606
|
const q = query.toLowerCase();
|
|
@@ -5724,8 +6629,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5724
6629
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5725
6630
|
const result = {};
|
|
5726
6631
|
profile.records.forEach((record) => {
|
|
5727
|
-
var
|
|
5728
|
-
const category = String((
|
|
6632
|
+
var _a2, _b, _c;
|
|
6633
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5729
6634
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5730
6635
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5731
6636
|
});
|
|
@@ -5804,8 +6709,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5804
6709
|
static aggregateByCategory(data, categories) {
|
|
5805
6710
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5806
6711
|
data.forEach((item) => {
|
|
5807
|
-
var
|
|
5808
|
-
const cat = (
|
|
6712
|
+
var _a2;
|
|
6713
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5809
6714
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5810
6715
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5811
6716
|
});
|
|
@@ -5813,17 +6718,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5813
6718
|
}
|
|
5814
6719
|
static extractTimeSeriesData(data) {
|
|
5815
6720
|
return data.map((item) => {
|
|
5816
|
-
var
|
|
6721
|
+
var _a2, _b, _c, _d, _e;
|
|
5817
6722
|
const meta = item.metadata || {};
|
|
5818
6723
|
return {
|
|
5819
|
-
timestamp: (_b = (
|
|
6724
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5820
6725
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5821
6726
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5822
6727
|
};
|
|
5823
6728
|
});
|
|
5824
6729
|
}
|
|
5825
6730
|
static extractNumericValue(meta) {
|
|
5826
|
-
var
|
|
6731
|
+
var _a2;
|
|
5827
6732
|
const preferredKeys = [
|
|
5828
6733
|
"value",
|
|
5829
6734
|
"count",
|
|
@@ -5838,7 +6743,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5838
6743
|
"price"
|
|
5839
6744
|
];
|
|
5840
6745
|
for (const key of preferredKeys) {
|
|
5841
|
-
const raw = (
|
|
6746
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5842
6747
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5843
6748
|
if (Number.isFinite(value)) return value;
|
|
5844
6749
|
}
|
|
@@ -5984,8 +6889,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5984
6889
|
let inStock = 0;
|
|
5985
6890
|
let outOfStock = 0;
|
|
5986
6891
|
data.forEach((d) => {
|
|
5987
|
-
var
|
|
5988
|
-
const cat = (
|
|
6892
|
+
var _a2, _b;
|
|
6893
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
5989
6894
|
if (cat === category) {
|
|
5990
6895
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
5991
6896
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -6029,9 +6934,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
6029
6934
|
}
|
|
6030
6935
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
6031
6936
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
6032
|
-
var
|
|
6937
|
+
var _a2;
|
|
6033
6938
|
if (!meta) return void 0;
|
|
6034
|
-
const mapping = (
|
|
6939
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
6035
6940
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
6036
6941
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
6037
6942
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -6040,13 +6945,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
6040
6945
|
return resolveMetadataValue(meta, uiKey);
|
|
6041
6946
|
}
|
|
6042
6947
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6043
|
-
var
|
|
6948
|
+
var _a2;
|
|
6044
6949
|
const meta = item.metadata || {};
|
|
6045
6950
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6046
6951
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6047
6952
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6048
6953
|
const description = this.cleanProductDescription(
|
|
6049
|
-
(
|
|
6954
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6050
6955
|
);
|
|
6051
6956
|
if (name || this.isProductData(item)) {
|
|
6052
6957
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6154,10 +7059,10 @@ RULES:
|
|
|
6154
7059
|
}
|
|
6155
7060
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6156
7061
|
const items = sources.map((s, i) => {
|
|
6157
|
-
var
|
|
7062
|
+
var _a2, _b, _c, _d;
|
|
6158
7063
|
return {
|
|
6159
7064
|
index: i + 1,
|
|
6160
|
-
content: (_b = (
|
|
7065
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6161
7066
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6162
7067
|
score: (_d = s.score) != null ? _d : 0
|
|
6163
7068
|
};
|
|
@@ -6350,9 +7255,11 @@ var Pipeline = class {
|
|
|
6350
7255
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6351
7256
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6352
7257
|
this.initialised = false;
|
|
6353
|
-
|
|
7258
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7259
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7260
|
+
var _a2, _b, _c, _d, _e;
|
|
6354
7261
|
this.chunker = new DocumentChunker(
|
|
6355
|
-
(_b = (
|
|
7262
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6356
7263
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6357
7264
|
);
|
|
6358
7265
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6368,7 +7275,7 @@ var Pipeline = class {
|
|
|
6368
7275
|
return this.initialised ? this.llmProvider : void 0;
|
|
6369
7276
|
}
|
|
6370
7277
|
async initialize() {
|
|
6371
|
-
var
|
|
7278
|
+
var _a2, _b, _c;
|
|
6372
7279
|
if (this.initialised) return;
|
|
6373
7280
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6374
7281
|
|
|
@@ -6411,12 +7318,47 @@ var Pipeline = class {
|
|
|
6411
7318
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6412
7319
|
}
|
|
6413
7320
|
await this.vectorDB.initialize();
|
|
6414
|
-
if (((
|
|
7321
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7322
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7323
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7324
|
+
llmProvider: this.llmProvider,
|
|
7325
|
+
mcpRegistry: this.mcpRegistry,
|
|
7326
|
+
documentSearch: async (query) => {
|
|
7327
|
+
return this.runNormalQuery(query);
|
|
7328
|
+
}
|
|
7329
|
+
});
|
|
6415
7330
|
this.agent = new LangChainAgent(this, this.config);
|
|
6416
7331
|
await this.agent.initialize(this.llmProvider);
|
|
6417
7332
|
}
|
|
7333
|
+
if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
|
|
7334
|
+
await this.loadColdContext(this.config.projectId);
|
|
7335
|
+
}
|
|
6418
7336
|
this.initialised = true;
|
|
6419
7337
|
}
|
|
7338
|
+
async loadColdContext(ns) {
|
|
7339
|
+
var _a2, _b;
|
|
7340
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7341
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7342
|
+
try {
|
|
7343
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7344
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7345
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7346
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7347
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7348
|
+
if (coldMatches.length > 0) {
|
|
7349
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7350
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7351
|
+
this.coldContexts.set(ns, formatted);
|
|
7352
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7353
|
+
} else {
|
|
7354
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7355
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7356
|
+
}
|
|
7357
|
+
} catch (err) {
|
|
7358
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7359
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7360
|
+
}
|
|
7361
|
+
}
|
|
6420
7362
|
/**
|
|
6421
7363
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6422
7364
|
*/
|
|
@@ -6448,12 +7390,12 @@ var Pipeline = class {
|
|
|
6448
7390
|
}
|
|
6449
7391
|
/** Step 1: Chunk the document content. */
|
|
6450
7392
|
async prepareChunks(doc) {
|
|
6451
|
-
var
|
|
7393
|
+
var _a2, _b;
|
|
6452
7394
|
if (this.llamaIngestor) {
|
|
6453
7395
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6454
7396
|
docId: doc.docId,
|
|
6455
7397
|
metadata: doc.metadata,
|
|
6456
|
-
chunkSize: (
|
|
7398
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6457
7399
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6458
7400
|
});
|
|
6459
7401
|
}
|
|
@@ -6475,7 +7417,7 @@ var Pipeline = class {
|
|
|
6475
7417
|
embedBatchOptions
|
|
6476
7418
|
);
|
|
6477
7419
|
if (vectors.length !== chunks.length) {
|
|
6478
|
-
throw new
|
|
7420
|
+
throw new EmbeddingFailedException(
|
|
6479
7421
|
`[Pipeline] Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks. Check embedding provider logs for individual chunk failures.`
|
|
6480
7422
|
);
|
|
6481
7423
|
}
|
|
@@ -6524,12 +7466,37 @@ var Pipeline = class {
|
|
|
6524
7466
|
extractionOptions
|
|
6525
7467
|
);
|
|
6526
7468
|
}
|
|
7469
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7470
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7471
|
+
let reply = "";
|
|
7472
|
+
let sources = [];
|
|
7473
|
+
try {
|
|
7474
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7475
|
+
const chunk = temp.value;
|
|
7476
|
+
if (typeof chunk === "string") {
|
|
7477
|
+
reply += chunk;
|
|
7478
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7479
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7480
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7481
|
+
}
|
|
7482
|
+
}
|
|
7483
|
+
} catch (temp) {
|
|
7484
|
+
error = [temp];
|
|
7485
|
+
} finally {
|
|
7486
|
+
try {
|
|
7487
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7488
|
+
} finally {
|
|
7489
|
+
if (error)
|
|
7490
|
+
throw error[0];
|
|
7491
|
+
}
|
|
7492
|
+
}
|
|
7493
|
+
return { reply, sources };
|
|
7494
|
+
}
|
|
6527
7495
|
async ask(question, history = [], namespace) {
|
|
6528
|
-
var
|
|
7496
|
+
var _a2;
|
|
6529
7497
|
await this.initialize();
|
|
6530
|
-
if (((
|
|
6531
|
-
|
|
6532
|
-
return { reply: agentReply, sources: [] };
|
|
7498
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7499
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6533
7500
|
}
|
|
6534
7501
|
const stream = this.askStream(question, history, namespace);
|
|
6535
7502
|
let reply = "";
|
|
@@ -6561,6 +7528,47 @@ var Pipeline = class {
|
|
|
6561
7528
|
}
|
|
6562
7529
|
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
6563
7530
|
}
|
|
7531
|
+
askStream(_0) {
|
|
7532
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7533
|
+
var _a2;
|
|
7534
|
+
yield new __await(this.initialize());
|
|
7535
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7536
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7537
|
+
try {
|
|
7538
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7539
|
+
const chunk = temp.value;
|
|
7540
|
+
yield chunk;
|
|
7541
|
+
}
|
|
7542
|
+
} catch (temp) {
|
|
7543
|
+
error = [temp];
|
|
7544
|
+
} finally {
|
|
7545
|
+
try {
|
|
7546
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7547
|
+
} finally {
|
|
7548
|
+
if (error)
|
|
7549
|
+
throw error[0];
|
|
7550
|
+
}
|
|
7551
|
+
}
|
|
7552
|
+
return;
|
|
7553
|
+
}
|
|
7554
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7555
|
+
try {
|
|
7556
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7557
|
+
const chunk = temp2.value;
|
|
7558
|
+
yield chunk;
|
|
7559
|
+
}
|
|
7560
|
+
} catch (temp2) {
|
|
7561
|
+
error2 = [temp2];
|
|
7562
|
+
} finally {
|
|
7563
|
+
try {
|
|
7564
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7565
|
+
} finally {
|
|
7566
|
+
if (error2)
|
|
7567
|
+
throw error2[0];
|
|
7568
|
+
}
|
|
7569
|
+
}
|
|
7570
|
+
});
|
|
7571
|
+
}
|
|
6564
7572
|
/**
|
|
6565
7573
|
* High-performance streaming RAG flow.
|
|
6566
7574
|
* Yields text chunks first, then the retrieval metadata + observability trace at the end.
|
|
@@ -6571,12 +7579,12 @@ var Pipeline = class {
|
|
|
6571
7579
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6572
7580
|
* - SchemaMapper.train runs while answer generation streams
|
|
6573
7581
|
*/
|
|
6574
|
-
|
|
7582
|
+
askStreamInternal(_0) {
|
|
6575
7583
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6576
|
-
var
|
|
7584
|
+
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;
|
|
6577
7585
|
yield new __await(this.initialize());
|
|
6578
7586
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6579
|
-
const topK = (_b = (
|
|
7587
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6580
7588
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6581
7589
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6582
7590
|
const requestStart = performance.now();
|
|
@@ -6589,7 +7597,7 @@ var Pipeline = class {
|
|
|
6589
7597
|
}
|
|
6590
7598
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6591
7599
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6592
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7600
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6593
7601
|
if (numericPredicates.length > 0) {
|
|
6594
7602
|
filter.__numericPredicates = numericPredicates;
|
|
6595
7603
|
}
|
|
@@ -6655,6 +7663,32 @@ ${graphContext}
|
|
|
6655
7663
|
VECTOR CONTEXT:
|
|
6656
7664
|
${context}`;
|
|
6657
7665
|
}
|
|
7666
|
+
if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
|
|
7667
|
+
if (!this.coldContexts.has(ns)) {
|
|
7668
|
+
yield new __await(this.loadColdContext(ns));
|
|
7669
|
+
}
|
|
7670
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7671
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7672
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7673
|
+
${coldContext}
|
|
7674
|
+
|
|
7675
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7676
|
+
${context}`;
|
|
7677
|
+
}
|
|
7678
|
+
}
|
|
7679
|
+
yield {
|
|
7680
|
+
reply: "",
|
|
7681
|
+
sources: sources.map((s) => {
|
|
7682
|
+
var _a3;
|
|
7683
|
+
return {
|
|
7684
|
+
id: s.id,
|
|
7685
|
+
score: s.score,
|
|
7686
|
+
content: s.content,
|
|
7687
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7688
|
+
namespace: ns
|
|
7689
|
+
};
|
|
7690
|
+
})
|
|
7691
|
+
};
|
|
6658
7692
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6659
7693
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6660
7694
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6682,10 +7716,10 @@ ${context}`;
|
|
|
6682
7716
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6683
7717
|
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.)";
|
|
6684
7718
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6685
|
-
const isNativeThinking = isClaude37 && (((
|
|
7719
|
+
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);
|
|
6686
7720
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6687
7721
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6688
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7722
|
+
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);
|
|
6689
7723
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6690
7724
|
if (isSimulatedThinking) {
|
|
6691
7725
|
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.`)";
|
|
@@ -6693,7 +7727,7 @@ ${context}`;
|
|
|
6693
7727
|
const hardenedHistory = [...history];
|
|
6694
7728
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6695
7729
|
const messages = [...hardenedHistory, userQuestion];
|
|
6696
|
-
const systemPrompt = (
|
|
7730
|
+
const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
|
|
6697
7731
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6698
7732
|
let fullReply = "";
|
|
6699
7733
|
let thinkingText = "";
|
|
@@ -6804,7 +7838,7 @@ ${context}`;
|
|
|
6804
7838
|
}
|
|
6805
7839
|
yield fullReply;
|
|
6806
7840
|
}
|
|
6807
|
-
const runHallucination = ((
|
|
7841
|
+
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;
|
|
6808
7842
|
if (runHallucination) {
|
|
6809
7843
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6810
7844
|
}
|
|
@@ -6813,7 +7847,7 @@ ${context}`;
|
|
|
6813
7847
|
const latency = {
|
|
6814
7848
|
embedMs: Math.round(embedMs),
|
|
6815
7849
|
retrieveMs: Math.round(retrieveMs),
|
|
6816
|
-
rerankMs: ((
|
|
7850
|
+
rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6817
7851
|
generateMs: Math.round(generateMs),
|
|
6818
7852
|
totalMs: Math.round(totalMs)
|
|
6819
7853
|
};
|
|
@@ -6826,33 +7860,63 @@ ${context}`;
|
|
|
6826
7860
|
totalTokens: promptTokens + completionTokens,
|
|
6827
7861
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6828
7862
|
};
|
|
7863
|
+
const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
|
|
6829
7864
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6830
7865
|
uiTransformationPromise,
|
|
6831
|
-
hallucinationScoringPromise
|
|
7866
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6832
7867
|
]));
|
|
6833
|
-
const
|
|
7868
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6834
7869
|
requestId,
|
|
6835
7870
|
query: question,
|
|
6836
7871
|
rewrittenQuery,
|
|
6837
7872
|
systemPrompt,
|
|
6838
7873
|
userPrompt: question + finalRestrictionSuffix,
|
|
6839
7874
|
chunks: sources.map((s) => {
|
|
6840
|
-
var
|
|
7875
|
+
var _a3;
|
|
6841
7876
|
return {
|
|
6842
7877
|
id: s.id,
|
|
6843
7878
|
score: s.score,
|
|
6844
7879
|
content: s.content,
|
|
6845
|
-
metadata: (
|
|
7880
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6846
7881
|
namespace: ns
|
|
6847
7882
|
};
|
|
6848
7883
|
}),
|
|
6849
7884
|
latency,
|
|
6850
7885
|
tokens,
|
|
6851
7886
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6852
|
-
},
|
|
6853
|
-
hallucinationScore:
|
|
6854
|
-
hallucinationReason:
|
|
7887
|
+
}, hScore ? {
|
|
7888
|
+
hallucinationScore: hScore.score,
|
|
7889
|
+
hallucinationReason: hScore.reason
|
|
6855
7890
|
} : {});
|
|
7891
|
+
const trace = buildTrace(hallucinationResult);
|
|
7892
|
+
if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
|
|
7893
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7894
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7895
|
+
(async () => {
|
|
7896
|
+
try {
|
|
7897
|
+
let finalTrace = trace;
|
|
7898
|
+
if (!awaitHallucination && runHallucination) {
|
|
7899
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7900
|
+
if (backgroundScoreResult) {
|
|
7901
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7902
|
+
}
|
|
7903
|
+
}
|
|
7904
|
+
await fetch(absoluteUrl, {
|
|
7905
|
+
method: "POST",
|
|
7906
|
+
headers: {
|
|
7907
|
+
"Content-Type": "application/json"
|
|
7908
|
+
},
|
|
7909
|
+
body: JSON.stringify({
|
|
7910
|
+
trace: finalTrace,
|
|
7911
|
+
licenseKey: this.config.licenseKey,
|
|
7912
|
+
projectId: ns
|
|
7913
|
+
})
|
|
7914
|
+
});
|
|
7915
|
+
} catch (err) {
|
|
7916
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
7917
|
+
}
|
|
7918
|
+
})();
|
|
7919
|
+
}
|
|
6856
7920
|
yield {
|
|
6857
7921
|
reply: "",
|
|
6858
7922
|
sources,
|
|
@@ -6872,7 +7936,7 @@ ${context}`;
|
|
|
6872
7936
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6873
7937
|
*/
|
|
6874
7938
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6875
|
-
var
|
|
7939
|
+
var _a2;
|
|
6876
7940
|
if (!sources || sources.length === 0) {
|
|
6877
7941
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6878
7942
|
}
|
|
@@ -6886,7 +7950,7 @@ ${context}`;
|
|
|
6886
7950
|
);
|
|
6887
7951
|
}
|
|
6888
7952
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6889
|
-
const disableLlmUiTransform = ((
|
|
7953
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6890
7954
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6891
7955
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6892
7956
|
}
|
|
@@ -6904,9 +7968,9 @@ ${context}`;
|
|
|
6904
7968
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6905
7969
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6906
7970
|
})).sort((a, b) => {
|
|
6907
|
-
var
|
|
7971
|
+
var _a2, _b;
|
|
6908
7972
|
const primary = predicates[0];
|
|
6909
|
-
const aValue = (
|
|
7973
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6910
7974
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6911
7975
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6912
7976
|
});
|
|
@@ -6978,8 +8042,8 @@ ${context}`;
|
|
|
6978
8042
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6979
8043
|
}
|
|
6980
8044
|
async retrieve(query, options) {
|
|
6981
|
-
var
|
|
6982
|
-
const ns = (
|
|
8045
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
8046
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
6983
8047
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6984
8048
|
const cacheKey = `${ns}::${query}`;
|
|
6985
8049
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -7011,7 +8075,7 @@ ${context}`;
|
|
|
7011
8075
|
) : [];
|
|
7012
8076
|
const resolvedSources = [];
|
|
7013
8077
|
for (const source of sources) {
|
|
7014
|
-
const parentId = (
|
|
8078
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
7015
8079
|
if (parentId) {
|
|
7016
8080
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
7017
8081
|
resolvedSources.push(source);
|
|
@@ -7071,18 +8135,100 @@ Suggestions:`;
|
|
|
7071
8135
|
systemPrompt: "You are a helpful assistant that generates search suggestions based on the provided snippets. Focus on questions that can be answered by the context, keep each under 10 words, and return ONLY a JSON array of strings.",
|
|
7072
8136
|
temperature: 0
|
|
7073
8137
|
}
|
|
7074
|
-
);
|
|
7075
|
-
const match = response.match(/\[[\s\S]*\]/);
|
|
7076
|
-
if (match) {
|
|
7077
|
-
const suggestions = JSON.parse(match[0]);
|
|
7078
|
-
if (Array.isArray(suggestions)) {
|
|
7079
|
-
return suggestions.map((s) => String(s)).slice(0, 5);
|
|
8138
|
+
);
|
|
8139
|
+
const match = response.match(/\[[\s\S]*\]/);
|
|
8140
|
+
if (match) {
|
|
8141
|
+
const suggestions = JSON.parse(match[0]);
|
|
8142
|
+
if (Array.isArray(suggestions)) {
|
|
8143
|
+
return suggestions.map((s) => String(s)).slice(0, 5);
|
|
8144
|
+
}
|
|
8145
|
+
}
|
|
8146
|
+
} catch (error) {
|
|
8147
|
+
console.error("[Pipeline] Failed to generate suggestions:", error);
|
|
8148
|
+
}
|
|
8149
|
+
return [];
|
|
8150
|
+
}
|
|
8151
|
+
};
|
|
8152
|
+
|
|
8153
|
+
// src/core/Retrivora.ts
|
|
8154
|
+
var Retrivora = class {
|
|
8155
|
+
constructor(config) {
|
|
8156
|
+
this.config = ConfigResolver.resolveUniversal(config);
|
|
8157
|
+
this.pipeline = new Pipeline(this.config);
|
|
8158
|
+
}
|
|
8159
|
+
async initialize() {
|
|
8160
|
+
var _a2;
|
|
8161
|
+
try {
|
|
8162
|
+
await ConfigValidator.validateAndThrow(this.config);
|
|
8163
|
+
LicenseVerifier.verify(
|
|
8164
|
+
this.config.licenseKey,
|
|
8165
|
+
this.config.projectId,
|
|
8166
|
+
(_a2 = this.config.vectorDb) == null ? void 0 : _a2.provider
|
|
8167
|
+
);
|
|
8168
|
+
} catch (err) {
|
|
8169
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8170
|
+
}
|
|
8171
|
+
try {
|
|
8172
|
+
await this.pipeline.initialize();
|
|
8173
|
+
} catch (err) {
|
|
8174
|
+
throw wrapError(err, "AUTHENTICATION_ERROR");
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
8177
|
+
async ingest(documents, namespace) {
|
|
8178
|
+
try {
|
|
8179
|
+
return await this.pipeline.ingest(documents, namespace);
|
|
8180
|
+
} catch (err) {
|
|
8181
|
+
const msg = String(err);
|
|
8182
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8183
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8184
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8185
|
+
}
|
|
8186
|
+
throw wrapError(err, defaultCode);
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
async ask(question, history = [], namespace) {
|
|
8190
|
+
try {
|
|
8191
|
+
return await this.pipeline.ask(question, history, namespace);
|
|
8192
|
+
} catch (err) {
|
|
8193
|
+
const msg = String(err);
|
|
8194
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8195
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8196
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8197
|
+
}
|
|
8198
|
+
throw wrapError(err, defaultCode);
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
askStream(_0) {
|
|
8202
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
8203
|
+
try {
|
|
8204
|
+
const stream = this.pipeline.askStream(question, history, namespace);
|
|
8205
|
+
try {
|
|
8206
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
8207
|
+
const chunk = temp.value;
|
|
8208
|
+
yield chunk;
|
|
8209
|
+
}
|
|
8210
|
+
} catch (temp) {
|
|
8211
|
+
error = [temp];
|
|
8212
|
+
} finally {
|
|
8213
|
+
try {
|
|
8214
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
8215
|
+
} finally {
|
|
8216
|
+
if (error)
|
|
8217
|
+
throw error[0];
|
|
8218
|
+
}
|
|
8219
|
+
}
|
|
8220
|
+
} catch (err) {
|
|
8221
|
+
const msg = String(err);
|
|
8222
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8223
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8224
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
7080
8225
|
}
|
|
8226
|
+
throw wrapError(err, defaultCode);
|
|
7081
8227
|
}
|
|
7082
|
-
}
|
|
7083
|
-
|
|
7084
|
-
|
|
7085
|
-
return
|
|
8228
|
+
});
|
|
8229
|
+
}
|
|
8230
|
+
getPipeline() {
|
|
8231
|
+
return this.pipeline;
|
|
7086
8232
|
}
|
|
7087
8233
|
};
|
|
7088
8234
|
|
|
@@ -7192,9 +8338,20 @@ var ProviderHealthCheck = class {
|
|
|
7192
8338
|
// src/core/VectorPlugin.ts
|
|
7193
8339
|
var VectorPlugin = class {
|
|
7194
8340
|
constructor(hostConfig) {
|
|
7195
|
-
|
|
7196
|
-
this.
|
|
7197
|
-
this.
|
|
8341
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8342
|
+
this.config = resolvedConfig;
|
|
8343
|
+
this.validationPromise = (async () => {
|
|
8344
|
+
var _a2;
|
|
8345
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8346
|
+
LicenseVerifier.verify(
|
|
8347
|
+
resolvedConfig.licenseKey,
|
|
8348
|
+
resolvedConfig.projectId,
|
|
8349
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8350
|
+
);
|
|
8351
|
+
})();
|
|
8352
|
+
this.validationPromise.catch(() => {
|
|
8353
|
+
});
|
|
8354
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7198
8355
|
}
|
|
7199
8356
|
/**
|
|
7200
8357
|
* Get the current resolved configuration.
|
|
@@ -7227,55 +8384,93 @@ var VectorPlugin = class {
|
|
|
7227
8384
|
* Run a chat query.
|
|
7228
8385
|
*/
|
|
7229
8386
|
async chat(message, history = [], namespace) {
|
|
7230
|
-
|
|
7231
|
-
|
|
8387
|
+
try {
|
|
8388
|
+
await this.validationPromise;
|
|
8389
|
+
} catch (err) {
|
|
8390
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8391
|
+
}
|
|
8392
|
+
try {
|
|
8393
|
+
return await this.pipeline.ask(message, history, namespace);
|
|
8394
|
+
} catch (err) {
|
|
8395
|
+
const msg = String(err);
|
|
8396
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8397
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8398
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8399
|
+
}
|
|
8400
|
+
throw wrapError(err, defaultCode);
|
|
8401
|
+
}
|
|
7232
8402
|
}
|
|
7233
8403
|
/**
|
|
7234
8404
|
* Run a streaming chat query.
|
|
7235
8405
|
*/
|
|
7236
8406
|
chatStream(_0) {
|
|
7237
8407
|
return __asyncGenerator(this, arguments, function* (message, history = [], namespace) {
|
|
7238
|
-
|
|
7239
|
-
|
|
8408
|
+
try {
|
|
8409
|
+
yield new __await(this.validationPromise);
|
|
8410
|
+
} catch (err) {
|
|
8411
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8412
|
+
}
|
|
8413
|
+
try {
|
|
8414
|
+
const stream = this.pipeline.askStream(message, history, namespace);
|
|
8415
|
+
try {
|
|
8416
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
8417
|
+
const chunk = temp.value;
|
|
8418
|
+
yield chunk;
|
|
8419
|
+
}
|
|
8420
|
+
} catch (temp) {
|
|
8421
|
+
error = [temp];
|
|
8422
|
+
} finally {
|
|
8423
|
+
try {
|
|
8424
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
8425
|
+
} finally {
|
|
8426
|
+
if (error)
|
|
8427
|
+
throw error[0];
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
} catch (err) {
|
|
8431
|
+
const msg = String(err);
|
|
8432
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8433
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8434
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8435
|
+
}
|
|
8436
|
+
throw wrapError(err, defaultCode);
|
|
8437
|
+
}
|
|
7240
8438
|
});
|
|
7241
8439
|
}
|
|
7242
8440
|
/**
|
|
7243
8441
|
* Ingest documents into the vector database.
|
|
7244
8442
|
*/
|
|
7245
8443
|
async ingest(documents, namespace) {
|
|
7246
|
-
|
|
7247
|
-
|
|
8444
|
+
try {
|
|
8445
|
+
await this.validationPromise;
|
|
8446
|
+
} catch (err) {
|
|
8447
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8448
|
+
}
|
|
8449
|
+
try {
|
|
8450
|
+
return await this.pipeline.ingest(documents, namespace);
|
|
8451
|
+
} catch (err) {
|
|
8452
|
+
const msg = String(err);
|
|
8453
|
+
let defaultCode = "RETRIEVAL_FAILED";
|
|
8454
|
+
if (msg.includes("Embed") || msg.includes("embed")) {
|
|
8455
|
+
defaultCode = "EMBEDDING_FAILED";
|
|
8456
|
+
}
|
|
8457
|
+
throw wrapError(err, defaultCode);
|
|
8458
|
+
}
|
|
7248
8459
|
}
|
|
7249
8460
|
/**
|
|
7250
8461
|
* Get auto-suggestions based on a query prefix.
|
|
7251
8462
|
*/
|
|
7252
8463
|
async getSuggestions(query, namespace) {
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
}
|
|
7264
|
-
async initialize() {
|
|
7265
|
-
await ConfigValidator.validateAndThrow(this.config);
|
|
7266
|
-
await this.pipeline.initialize();
|
|
7267
|
-
}
|
|
7268
|
-
async ingest(documents, namespace) {
|
|
7269
|
-
return this.pipeline.ingest(documents, namespace);
|
|
7270
|
-
}
|
|
7271
|
-
async ask(question, history = [], namespace) {
|
|
7272
|
-
return this.pipeline.ask(question, history, namespace);
|
|
7273
|
-
}
|
|
7274
|
-
askStream(question, history = [], namespace) {
|
|
7275
|
-
return this.pipeline.askStream(question, history, namespace);
|
|
7276
|
-
}
|
|
7277
|
-
getPipeline() {
|
|
7278
|
-
return this.pipeline;
|
|
8464
|
+
try {
|
|
8465
|
+
await this.validationPromise;
|
|
8466
|
+
} catch (err) {
|
|
8467
|
+
throw wrapError(err, "CONFIGURATION_ERROR");
|
|
8468
|
+
}
|
|
8469
|
+
try {
|
|
8470
|
+
return await this.pipeline.getSuggestions(query, namespace);
|
|
8471
|
+
} catch (err) {
|
|
8472
|
+
throw wrapError(err, "RETRIEVAL_FAILED");
|
|
8473
|
+
}
|
|
7279
8474
|
}
|
|
7280
8475
|
};
|
|
7281
8476
|
|
|
@@ -7292,13 +8487,13 @@ var ConfigBuilder = class {
|
|
|
7292
8487
|
* Configure the vector database provider
|
|
7293
8488
|
*/
|
|
7294
8489
|
vectorDb(provider, options) {
|
|
7295
|
-
var
|
|
8490
|
+
var _a2;
|
|
7296
8491
|
if (provider === "auto") {
|
|
7297
8492
|
this._vectorDb = this._autoDetectVectorDb();
|
|
7298
8493
|
} else {
|
|
7299
8494
|
this._vectorDb = {
|
|
7300
8495
|
provider,
|
|
7301
|
-
indexName: (
|
|
8496
|
+
indexName: (_a2 = options == null ? void 0 : options.indexName) != null ? _a2 : "default",
|
|
7302
8497
|
options: __spreadValues({}, options)
|
|
7303
8498
|
};
|
|
7304
8499
|
}
|
|
@@ -7308,7 +8503,7 @@ var ConfigBuilder = class {
|
|
|
7308
8503
|
* Configure the LLM provider for chat
|
|
7309
8504
|
*/
|
|
7310
8505
|
llm(provider, model, apiKey, options) {
|
|
7311
|
-
var
|
|
8506
|
+
var _a2, _b;
|
|
7312
8507
|
if (provider === "auto") {
|
|
7313
8508
|
this._llm = this._autoDetectLLM();
|
|
7314
8509
|
} else {
|
|
@@ -7317,7 +8512,7 @@ var ConfigBuilder = class {
|
|
|
7317
8512
|
model: model != null ? model : "default-model",
|
|
7318
8513
|
apiKey,
|
|
7319
8514
|
systemPrompt: options == null ? void 0 : options.systemPrompt,
|
|
7320
|
-
maxTokens: (
|
|
8515
|
+
maxTokens: (_a2 = options == null ? void 0 : options.maxTokens) != null ? _a2 : 1024,
|
|
7321
8516
|
temperature: (_b = options == null ? void 0 : options.temperature) != null ? _b : 0.7,
|
|
7322
8517
|
baseUrl: options == null ? void 0 : options.baseUrl,
|
|
7323
8518
|
options
|
|
@@ -7360,8 +8555,8 @@ var ConfigBuilder = class {
|
|
|
7360
8555
|
* Set RAG-specific pipeline parameters
|
|
7361
8556
|
*/
|
|
7362
8557
|
rag(options) {
|
|
7363
|
-
var
|
|
7364
|
-
this._rag = __spreadValues(__spreadValues({}, (
|
|
8558
|
+
var _a2;
|
|
8559
|
+
this._rag = __spreadValues(__spreadValues({}, (_a2 = this._rag) != null ? _a2 : {}), options);
|
|
7365
8560
|
return this;
|
|
7366
8561
|
}
|
|
7367
8562
|
/**
|
|
@@ -7377,7 +8572,7 @@ var ConfigBuilder = class {
|
|
|
7377
8572
|
* Throws if required fields (projectId, vectorDb, llm, embedding) are not set.
|
|
7378
8573
|
*/
|
|
7379
8574
|
build() {
|
|
7380
|
-
var
|
|
8575
|
+
var _a2;
|
|
7381
8576
|
const missing = [];
|
|
7382
8577
|
if (!this._projectId) missing.push('projectId (call .projectId("my-app"))');
|
|
7383
8578
|
if (!this._vectorDb) missing.push('vectorDb (call .vectorDb("pinecone", { ... }))');
|
|
@@ -7389,7 +8584,7 @@ var ConfigBuilder = class {
|
|
|
7389
8584
|
${missing.join("\n ")}`
|
|
7390
8585
|
);
|
|
7391
8586
|
}
|
|
7392
|
-
const ragConfig = (
|
|
8587
|
+
const ragConfig = (_a2 = this._rag) != null ? _a2 : { chunkSize: 1e3, chunkOverlap: 200, topK: 5 };
|
|
7393
8588
|
if (process.env.RAG_USE_GRAPH_RETRIEVAL === "true") {
|
|
7394
8589
|
ragConfig.useGraphRetrieval = true;
|
|
7395
8590
|
}
|
|
@@ -7485,8 +8680,8 @@ var DocumentParser = class {
|
|
|
7485
8680
|
* Extract text from a File or Buffer based on its type.
|
|
7486
8681
|
*/
|
|
7487
8682
|
static async parse(file, fileName, mimeType) {
|
|
7488
|
-
var
|
|
7489
|
-
const extension = (
|
|
8683
|
+
var _a2;
|
|
8684
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7490
8685
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7491
8686
|
return this.readAsText(file);
|
|
7492
8687
|
}
|
|
@@ -7553,6 +8748,497 @@ init_UniversalVectorProvider();
|
|
|
7553
8748
|
|
|
7554
8749
|
// src/handlers/index.ts
|
|
7555
8750
|
import { NextResponse } from "next/server";
|
|
8751
|
+
|
|
8752
|
+
// src/core/DatabaseStorage.ts
|
|
8753
|
+
import * as fs from "fs";
|
|
8754
|
+
import * as path from "path";
|
|
8755
|
+
var DatabaseStorage = class {
|
|
8756
|
+
constructor(config) {
|
|
8757
|
+
// Dynamic PG Pool
|
|
8758
|
+
this.pgPool = null;
|
|
8759
|
+
// Dynamic MongoDB Client
|
|
8760
|
+
this.mongoClient = null;
|
|
8761
|
+
this.mongoDbName = "";
|
|
8762
|
+
// Filesystem fallback configuration
|
|
8763
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8764
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8765
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8766
|
+
var _a2, _b, _c, _d, _e;
|
|
8767
|
+
this.config = config;
|
|
8768
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8769
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8770
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8771
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8772
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8773
|
+
}
|
|
8774
|
+
/**
|
|
8775
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8776
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8777
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8778
|
+
*/
|
|
8779
|
+
checkPremiumSubscription() {
|
|
8780
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8781
|
+
return;
|
|
8782
|
+
}
|
|
8783
|
+
if (!this.config.licenseKey) {
|
|
8784
|
+
throw new Error(
|
|
8785
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8786
|
+
);
|
|
8787
|
+
}
|
|
8788
|
+
try {
|
|
8789
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8790
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8791
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8792
|
+
throw new Error(
|
|
8793
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8794
|
+
);
|
|
8795
|
+
}
|
|
8796
|
+
} catch (err) {
|
|
8797
|
+
throw new Error(
|
|
8798
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8799
|
+
);
|
|
8800
|
+
}
|
|
8801
|
+
}
|
|
8802
|
+
checkHistoryEnabled() {
|
|
8803
|
+
var _a2, _b;
|
|
8804
|
+
this.checkPremiumSubscription();
|
|
8805
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8806
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8807
|
+
}
|
|
8808
|
+
}
|
|
8809
|
+
checkFeedbackEnabled() {
|
|
8810
|
+
var _a2, _b;
|
|
8811
|
+
this.checkPremiumSubscription();
|
|
8812
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8813
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8814
|
+
}
|
|
8815
|
+
}
|
|
8816
|
+
async getPGPool() {
|
|
8817
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8818
|
+
const _g2 = global;
|
|
8819
|
+
if (_g2[globalKey]) {
|
|
8820
|
+
this.pgPool = _g2[globalKey];
|
|
8821
|
+
return this.pgPool;
|
|
8822
|
+
}
|
|
8823
|
+
const opts = this.config.vectorDb.options;
|
|
8824
|
+
if (!opts.connectionString) {
|
|
8825
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8826
|
+
}
|
|
8827
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8828
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8829
|
+
_g2[globalKey] = this.pgPool;
|
|
8830
|
+
const client = await this.pgPool.connect();
|
|
8831
|
+
try {
|
|
8832
|
+
await client.query(`
|
|
8833
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8834
|
+
id TEXT PRIMARY KEY,
|
|
8835
|
+
session_id TEXT NOT NULL,
|
|
8836
|
+
role TEXT NOT NULL,
|
|
8837
|
+
content TEXT NOT NULL,
|
|
8838
|
+
sources JSONB,
|
|
8839
|
+
ui_transformation JSONB,
|
|
8840
|
+
trace JSONB,
|
|
8841
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8842
|
+
)
|
|
8843
|
+
`);
|
|
8844
|
+
await client.query(`
|
|
8845
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8846
|
+
id TEXT PRIMARY KEY,
|
|
8847
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8848
|
+
session_id TEXT NOT NULL,
|
|
8849
|
+
rating TEXT NOT NULL,
|
|
8850
|
+
comment TEXT,
|
|
8851
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8852
|
+
)
|
|
8853
|
+
`);
|
|
8854
|
+
} finally {
|
|
8855
|
+
client.release();
|
|
8856
|
+
}
|
|
8857
|
+
return this.pgPool;
|
|
8858
|
+
}
|
|
8859
|
+
async getMongoClient() {
|
|
8860
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8861
|
+
const _g2 = global;
|
|
8862
|
+
if (_g2[globalKey]) {
|
|
8863
|
+
this.mongoClient = _g2[globalKey];
|
|
8864
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8865
|
+
return this.mongoClient;
|
|
8866
|
+
}
|
|
8867
|
+
const opts = this.config.vectorDb.options;
|
|
8868
|
+
if (!opts.uri || !opts.database) {
|
|
8869
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8870
|
+
}
|
|
8871
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8872
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8873
|
+
await this.mongoClient.connect();
|
|
8874
|
+
_g2[globalKey] = this.mongoClient;
|
|
8875
|
+
this.mongoDbName = opts.database;
|
|
8876
|
+
return this.mongoClient;
|
|
8877
|
+
}
|
|
8878
|
+
getMongoDb() {
|
|
8879
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8880
|
+
}
|
|
8881
|
+
// Helper for FS fallback reads
|
|
8882
|
+
readLocalFile(filePath) {
|
|
8883
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8884
|
+
try {
|
|
8885
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8886
|
+
return JSON.parse(raw) || [];
|
|
8887
|
+
} catch (e) {
|
|
8888
|
+
return [];
|
|
8889
|
+
}
|
|
8890
|
+
}
|
|
8891
|
+
// Helper for FS fallback writes
|
|
8892
|
+
writeLocalFile(filePath, data) {
|
|
8893
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8894
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8895
|
+
}
|
|
8896
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8897
|
+
}
|
|
8898
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8899
|
+
async saveMessage(sessionId, message) {
|
|
8900
|
+
this.checkHistoryEnabled();
|
|
8901
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8902
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8903
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8904
|
+
const pool = await this.getPGPool();
|
|
8905
|
+
await pool.query(
|
|
8906
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8907
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8908
|
+
ON CONFLICT (id) DO UPDATE
|
|
8909
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8910
|
+
[
|
|
8911
|
+
msgId,
|
|
8912
|
+
sessionId,
|
|
8913
|
+
message.role,
|
|
8914
|
+
message.content,
|
|
8915
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
8916
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
8917
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
8918
|
+
createdAt
|
|
8919
|
+
]
|
|
8920
|
+
);
|
|
8921
|
+
} else if (this.provider === "mongodb") {
|
|
8922
|
+
await this.getMongoClient();
|
|
8923
|
+
const db = this.getMongoDb();
|
|
8924
|
+
const col = db.collection(this.historyTableName);
|
|
8925
|
+
await col.updateOne(
|
|
8926
|
+
{ id: msgId },
|
|
8927
|
+
{
|
|
8928
|
+
$set: {
|
|
8929
|
+
id: msgId,
|
|
8930
|
+
session_id: sessionId,
|
|
8931
|
+
role: message.role,
|
|
8932
|
+
content: message.content,
|
|
8933
|
+
sources: message.sources || null,
|
|
8934
|
+
ui_transformation: message.uiTransformation || null,
|
|
8935
|
+
trace: message.trace || null,
|
|
8936
|
+
created_at: createdAt
|
|
8937
|
+
}
|
|
8938
|
+
},
|
|
8939
|
+
{ upsert: true }
|
|
8940
|
+
);
|
|
8941
|
+
} else {
|
|
8942
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8943
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
8944
|
+
const item = {
|
|
8945
|
+
id: msgId,
|
|
8946
|
+
session_id: sessionId,
|
|
8947
|
+
role: message.role,
|
|
8948
|
+
content: message.content,
|
|
8949
|
+
sources: message.sources || null,
|
|
8950
|
+
ui_transformation: message.uiTransformation || null,
|
|
8951
|
+
trace: message.trace || null,
|
|
8952
|
+
created_at: createdAt
|
|
8953
|
+
};
|
|
8954
|
+
if (index !== -1) {
|
|
8955
|
+
history[index] = item;
|
|
8956
|
+
} else {
|
|
8957
|
+
history.push(item);
|
|
8958
|
+
}
|
|
8959
|
+
this.writeLocalFile(this.historyFile, history);
|
|
8960
|
+
}
|
|
8961
|
+
}
|
|
8962
|
+
async getHistory(sessionId) {
|
|
8963
|
+
this.checkHistoryEnabled();
|
|
8964
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8965
|
+
const pool = await this.getPGPool();
|
|
8966
|
+
const res = await pool.query(
|
|
8967
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
8968
|
+
FROM ${this.historyTableName}
|
|
8969
|
+
WHERE session_id = $1
|
|
8970
|
+
ORDER BY created_at ASC`,
|
|
8971
|
+
[sessionId]
|
|
8972
|
+
);
|
|
8973
|
+
return res.rows;
|
|
8974
|
+
} else if (this.provider === "mongodb") {
|
|
8975
|
+
await this.getMongoClient();
|
|
8976
|
+
const db = this.getMongoDb();
|
|
8977
|
+
const col = db.collection(this.historyTableName);
|
|
8978
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
8979
|
+
return items.map((item) => ({
|
|
8980
|
+
id: item.id,
|
|
8981
|
+
role: item.role,
|
|
8982
|
+
content: item.content,
|
|
8983
|
+
sources: item.sources,
|
|
8984
|
+
uiTransformation: item.ui_transformation,
|
|
8985
|
+
trace: item.trace,
|
|
8986
|
+
createdAt: item.created_at
|
|
8987
|
+
}));
|
|
8988
|
+
} else {
|
|
8989
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8990
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
8991
|
+
}
|
|
8992
|
+
}
|
|
8993
|
+
async clearHistory(sessionId) {
|
|
8994
|
+
this.checkHistoryEnabled();
|
|
8995
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8996
|
+
const pool = await this.getPGPool();
|
|
8997
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
8998
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
8999
|
+
} else if (this.provider === "mongodb") {
|
|
9000
|
+
await this.getMongoClient();
|
|
9001
|
+
const db = this.getMongoDb();
|
|
9002
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
9003
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
9004
|
+
} else {
|
|
9005
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9006
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
9007
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
9008
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
9009
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
9010
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
9013
|
+
async listSessions() {
|
|
9014
|
+
this.checkHistoryEnabled();
|
|
9015
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9016
|
+
const pool = await this.getPGPool();
|
|
9017
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
9018
|
+
return res.rows.map((r) => r.session_id);
|
|
9019
|
+
} else if (this.provider === "mongodb") {
|
|
9020
|
+
await this.getMongoClient();
|
|
9021
|
+
const db = this.getMongoDb();
|
|
9022
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
9023
|
+
} else {
|
|
9024
|
+
const history = this.readLocalFile(this.historyFile);
|
|
9025
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
9026
|
+
return Array.from(sessions);
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
9030
|
+
async saveFeedback(feedback) {
|
|
9031
|
+
this.checkFeedbackEnabled();
|
|
9032
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9033
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9034
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9035
|
+
const pool = await this.getPGPool();
|
|
9036
|
+
await pool.query(
|
|
9037
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
9038
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
9039
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
9040
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
9041
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
9042
|
+
);
|
|
9043
|
+
} else if (this.provider === "mongodb") {
|
|
9044
|
+
await this.getMongoClient();
|
|
9045
|
+
const db = this.getMongoDb();
|
|
9046
|
+
const col = db.collection(this.feedbackTableName);
|
|
9047
|
+
await col.updateOne(
|
|
9048
|
+
{ message_id: feedback.messageId },
|
|
9049
|
+
{
|
|
9050
|
+
$set: {
|
|
9051
|
+
id,
|
|
9052
|
+
message_id: feedback.messageId,
|
|
9053
|
+
session_id: feedback.sessionId,
|
|
9054
|
+
rating: feedback.rating,
|
|
9055
|
+
comment: feedback.comment || null,
|
|
9056
|
+
created_at: createdAt
|
|
9057
|
+
}
|
|
9058
|
+
},
|
|
9059
|
+
{ upsert: true }
|
|
9060
|
+
);
|
|
9061
|
+
} else {
|
|
9062
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9063
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
9064
|
+
const item = {
|
|
9065
|
+
id,
|
|
9066
|
+
message_id: feedback.messageId,
|
|
9067
|
+
session_id: feedback.sessionId,
|
|
9068
|
+
rating: feedback.rating,
|
|
9069
|
+
comment: feedback.comment || null,
|
|
9070
|
+
created_at: createdAt
|
|
9071
|
+
};
|
|
9072
|
+
if (index !== -1) {
|
|
9073
|
+
list[index] = item;
|
|
9074
|
+
} else {
|
|
9075
|
+
list.push(item);
|
|
9076
|
+
}
|
|
9077
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
9078
|
+
}
|
|
9079
|
+
}
|
|
9080
|
+
async getFeedback(messageId) {
|
|
9081
|
+
this.checkFeedbackEnabled();
|
|
9082
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9083
|
+
const pool = await this.getPGPool();
|
|
9084
|
+
const res = await pool.query(
|
|
9085
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9086
|
+
FROM ${this.feedbackTableName}
|
|
9087
|
+
WHERE message_id = $1`,
|
|
9088
|
+
[messageId]
|
|
9089
|
+
);
|
|
9090
|
+
return res.rows[0] || null;
|
|
9091
|
+
} else if (this.provider === "mongodb") {
|
|
9092
|
+
await this.getMongoClient();
|
|
9093
|
+
const db = this.getMongoDb();
|
|
9094
|
+
const col = db.collection(this.feedbackTableName);
|
|
9095
|
+
const item = await col.findOne({ message_id: messageId });
|
|
9096
|
+
if (!item) return null;
|
|
9097
|
+
return {
|
|
9098
|
+
id: item.id,
|
|
9099
|
+
messageId: item.message_id,
|
|
9100
|
+
sessionId: item.session_id,
|
|
9101
|
+
rating: item.rating,
|
|
9102
|
+
comment: item.comment,
|
|
9103
|
+
createdAt: item.created_at
|
|
9104
|
+
};
|
|
9105
|
+
} else {
|
|
9106
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9107
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
9108
|
+
}
|
|
9109
|
+
}
|
|
9110
|
+
async listFeedback() {
|
|
9111
|
+
this.checkFeedbackEnabled();
|
|
9112
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
9113
|
+
const pool = await this.getPGPool();
|
|
9114
|
+
const res = await pool.query(
|
|
9115
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
9116
|
+
FROM ${this.feedbackTableName}
|
|
9117
|
+
ORDER BY created_at DESC`
|
|
9118
|
+
);
|
|
9119
|
+
return res.rows;
|
|
9120
|
+
} else if (this.provider === "mongodb") {
|
|
9121
|
+
await this.getMongoClient();
|
|
9122
|
+
const db = this.getMongoDb();
|
|
9123
|
+
const col = db.collection(this.feedbackTableName);
|
|
9124
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
9125
|
+
return items.map((item) => ({
|
|
9126
|
+
id: item.id,
|
|
9127
|
+
messageId: item.message_id,
|
|
9128
|
+
sessionId: item.session_id,
|
|
9129
|
+
rating: item.rating,
|
|
9130
|
+
comment: item.comment,
|
|
9131
|
+
createdAt: item.created_at
|
|
9132
|
+
}));
|
|
9133
|
+
} else {
|
|
9134
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
9135
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
9136
|
+
}
|
|
9137
|
+
}
|
|
9138
|
+
async disconnect() {
|
|
9139
|
+
if (this.pgPool) {
|
|
9140
|
+
await this.pgPool.end();
|
|
9141
|
+
this.pgPool = null;
|
|
9142
|
+
}
|
|
9143
|
+
if (this.mongoClient) {
|
|
9144
|
+
await this.mongoClient.close();
|
|
9145
|
+
this.mongoClient = null;
|
|
9146
|
+
}
|
|
9147
|
+
}
|
|
9148
|
+
};
|
|
9149
|
+
|
|
9150
|
+
// src/handlers/index.ts
|
|
9151
|
+
async function checkAuth(req, onAuthorize) {
|
|
9152
|
+
if (!onAuthorize) return null;
|
|
9153
|
+
try {
|
|
9154
|
+
const res = await onAuthorize(req);
|
|
9155
|
+
if (res === false) {
|
|
9156
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
9157
|
+
}
|
|
9158
|
+
if (res instanceof Response) {
|
|
9159
|
+
return res;
|
|
9160
|
+
}
|
|
9161
|
+
return null;
|
|
9162
|
+
} catch (err) {
|
|
9163
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
9164
|
+
return NextResponse.json({ error: msg }, { status: 401 });
|
|
9165
|
+
}
|
|
9166
|
+
}
|
|
9167
|
+
var RateLimiter = class {
|
|
9168
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
9169
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
9170
|
+
this.windowMs = windowMs;
|
|
9171
|
+
this.max = max;
|
|
9172
|
+
}
|
|
9173
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
9174
|
+
allow(key) {
|
|
9175
|
+
const now = Date.now();
|
|
9176
|
+
const cutoff = now - this.windowMs;
|
|
9177
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9178
|
+
existing.push(now);
|
|
9179
|
+
this.hits.set(key, existing);
|
|
9180
|
+
if (this.hits.size > 5e3) {
|
|
9181
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
9182
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
9185
|
+
return existing.length <= this.max;
|
|
9186
|
+
}
|
|
9187
|
+
retryAfterSec(key) {
|
|
9188
|
+
const now = Date.now();
|
|
9189
|
+
const cutoff = now - this.windowMs;
|
|
9190
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
9191
|
+
if (existing.length === 0) return 0;
|
|
9192
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
9193
|
+
}
|
|
9194
|
+
};
|
|
9195
|
+
var _g = global;
|
|
9196
|
+
var _a;
|
|
9197
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
9198
|
+
function getRateLimitKey(req) {
|
|
9199
|
+
var _a2, _b;
|
|
9200
|
+
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";
|
|
9201
|
+
return `ip:${ip}`;
|
|
9202
|
+
}
|
|
9203
|
+
function checkRateLimit(req) {
|
|
9204
|
+
const key = getRateLimitKey(req);
|
|
9205
|
+
if (!rateLimiter.allow(key)) {
|
|
9206
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
9207
|
+
return new Response(
|
|
9208
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
9209
|
+
{
|
|
9210
|
+
status: 429,
|
|
9211
|
+
headers: {
|
|
9212
|
+
"Content-Type": "application/json",
|
|
9213
|
+
"Retry-After": String(retryAfter),
|
|
9214
|
+
"X-RateLimit-Limit": "30",
|
|
9215
|
+
"X-RateLimit-Window": "60"
|
|
9216
|
+
}
|
|
9217
|
+
}
|
|
9218
|
+
);
|
|
9219
|
+
}
|
|
9220
|
+
return null;
|
|
9221
|
+
}
|
|
9222
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
9223
|
+
function sanitizeInput(raw) {
|
|
9224
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
9225
|
+
const trimmed = stripped.trim();
|
|
9226
|
+
if (!trimmed) {
|
|
9227
|
+
return { ok: false, error: "message must not be empty" };
|
|
9228
|
+
}
|
|
9229
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
9230
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
9231
|
+
}
|
|
9232
|
+
return { ok: true, value: trimmed };
|
|
9233
|
+
}
|
|
9234
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
9235
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
9236
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
9237
|
+
if (!_g[cacheKey]) {
|
|
9238
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
9239
|
+
}
|
|
9240
|
+
return _g[cacheKey];
|
|
9241
|
+
}
|
|
7556
9242
|
function sseFrame(payload) {
|
|
7557
9243
|
return `data: ${JSON.stringify(payload)}
|
|
7558
9244
|
|
|
@@ -7590,47 +9276,88 @@ var SSE_HEADERS = {
|
|
|
7590
9276
|
"X-Accel-Buffering": "no"
|
|
7591
9277
|
// Disable Nginx buffering for streaming
|
|
7592
9278
|
};
|
|
7593
|
-
function createChatHandler(configOrPlugin) {
|
|
7594
|
-
const plugin =
|
|
9279
|
+
function createChatHandler(configOrPlugin, options) {
|
|
9280
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9281
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9282
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7595
9283
|
return async function POST(req) {
|
|
9284
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9285
|
+
if (authResult) return authResult;
|
|
9286
|
+
const rateLimited = checkRateLimit(req);
|
|
9287
|
+
if (rateLimited) return rateLimited;
|
|
7596
9288
|
try {
|
|
7597
9289
|
const body = await req.json();
|
|
7598
|
-
const { message, history = [], namespace } = body;
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
9290
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9291
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9292
|
+
if (!sanitized.ok) {
|
|
9293
|
+
return NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
9294
|
+
}
|
|
9295
|
+
const message = sanitized.value;
|
|
9296
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9297
|
+
await storage.saveMessage(sessionId, {
|
|
9298
|
+
id: userMsgId,
|
|
9299
|
+
role: "user",
|
|
9300
|
+
content: message
|
|
9301
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7602
9302
|
const result = await plugin.chat(message, history, namespace);
|
|
7603
|
-
|
|
9303
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9304
|
+
await storage.saveMessage(sessionId, {
|
|
9305
|
+
id: assistantMsgId,
|
|
9306
|
+
role: "assistant",
|
|
9307
|
+
content: result.reply,
|
|
9308
|
+
sources: result.sources,
|
|
9309
|
+
uiTransformation: result.ui_transformation,
|
|
9310
|
+
trace: result.trace
|
|
9311
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
9312
|
+
return NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
9313
|
+
messageId: assistantMsgId,
|
|
9314
|
+
userMessageId: userMsgId
|
|
9315
|
+
}));
|
|
7604
9316
|
} catch (err) {
|
|
7605
9317
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7606
9318
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
7607
9319
|
}
|
|
7608
9320
|
};
|
|
7609
9321
|
}
|
|
7610
|
-
function createStreamHandler(configOrPlugin) {
|
|
7611
|
-
const plugin =
|
|
9322
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
9323
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9324
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9325
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7612
9326
|
return async function POST(req) {
|
|
9327
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9328
|
+
if (authResult) return authResult;
|
|
9329
|
+
const rateLimited = checkRateLimit(req);
|
|
9330
|
+
if (rateLimited) return rateLimited;
|
|
7613
9331
|
let body;
|
|
7614
9332
|
try {
|
|
7615
9333
|
body = await req.json();
|
|
7616
9334
|
} catch (e) {
|
|
7617
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
9335
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7618
9336
|
status: 400,
|
|
7619
9337
|
headers: { "Content-Type": "application/json" }
|
|
7620
9338
|
});
|
|
7621
9339
|
}
|
|
7622
|
-
const { message, history = [], namespace } = body;
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
9340
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
9341
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
9342
|
+
if (!sanitized.ok) {
|
|
9343
|
+
return new Response(
|
|
9344
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9345
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9346
|
+
);
|
|
7628
9347
|
}
|
|
9348
|
+
const message = sanitized.value;
|
|
9349
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9350
|
+
await storage.saveMessage(sessionId, {
|
|
9351
|
+
id: userMsgId,
|
|
9352
|
+
role: "user",
|
|
9353
|
+
content: message
|
|
9354
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9355
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7629
9356
|
const encoder = new TextEncoder();
|
|
7630
9357
|
let isActive = true;
|
|
7631
9358
|
const stream = new ReadableStream({
|
|
7632
9359
|
async start(controller) {
|
|
7633
|
-
var
|
|
9360
|
+
var _a2;
|
|
7634
9361
|
const enqueue = (text) => {
|
|
7635
9362
|
if (!isActive) return;
|
|
7636
9363
|
try {
|
|
@@ -7641,11 +9368,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7641
9368
|
};
|
|
7642
9369
|
try {
|
|
7643
9370
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9371
|
+
let fullReply = "";
|
|
7644
9372
|
try {
|
|
7645
9373
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7646
9374
|
const chunk = temp.value;
|
|
7647
9375
|
if (!isActive) break;
|
|
7648
9376
|
if (typeof chunk === "string") {
|
|
9377
|
+
fullReply += chunk;
|
|
7649
9378
|
enqueue(sseTextFrame(chunk));
|
|
7650
9379
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7651
9380
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7658,9 +9387,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7658
9387
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7659
9388
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7660
9389
|
}
|
|
9390
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7661
9391
|
if (sources.length > 0) {
|
|
7662
9392
|
try {
|
|
7663
|
-
|
|
9393
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7664
9394
|
if (uiTransformation) {
|
|
7665
9395
|
enqueue(sseUIFrame(uiTransformation));
|
|
7666
9396
|
}
|
|
@@ -7668,11 +9398,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7668
9398
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7669
9399
|
try {
|
|
7670
9400
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7671
|
-
if (fallback)
|
|
9401
|
+
if (fallback) {
|
|
9402
|
+
uiTransformation = fallback;
|
|
9403
|
+
enqueue(sseUIFrame(fallback));
|
|
9404
|
+
}
|
|
7672
9405
|
} catch (e) {
|
|
7673
9406
|
}
|
|
7674
9407
|
}
|
|
7675
9408
|
}
|
|
9409
|
+
await storage.saveMessage(sessionId, {
|
|
9410
|
+
id: assistantMsgId,
|
|
9411
|
+
role: "assistant",
|
|
9412
|
+
content: fullReply,
|
|
9413
|
+
sources,
|
|
9414
|
+
uiTransformation,
|
|
9415
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9416
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7676
9417
|
}
|
|
7677
9418
|
}
|
|
7678
9419
|
} catch (temp) {
|
|
@@ -7709,12 +9450,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7709
9450
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7710
9451
|
}
|
|
7711
9452
|
});
|
|
7712
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9453
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7713
9454
|
};
|
|
7714
9455
|
}
|
|
7715
|
-
function createIngestHandler(configOrPlugin) {
|
|
7716
|
-
const plugin =
|
|
9456
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9457
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9458
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7717
9459
|
return async function POST(req) {
|
|
9460
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9461
|
+
if (authResult) return authResult;
|
|
7718
9462
|
try {
|
|
7719
9463
|
const body = await req.json();
|
|
7720
9464
|
const { documents, namespace } = body;
|
|
@@ -7729,9 +9473,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7729
9473
|
}
|
|
7730
9474
|
};
|
|
7731
9475
|
}
|
|
7732
|
-
function createHealthHandler(configOrPlugin) {
|
|
7733
|
-
const plugin =
|
|
7734
|
-
|
|
9476
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9477
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9478
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9479
|
+
return async function GET(req) {
|
|
9480
|
+
if (req) {
|
|
9481
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9482
|
+
if (authResult) return authResult;
|
|
9483
|
+
}
|
|
7735
9484
|
try {
|
|
7736
9485
|
const health = await plugin.checkHealth();
|
|
7737
9486
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7746,9 +9495,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7746
9495
|
}
|
|
7747
9496
|
};
|
|
7748
9497
|
}
|
|
7749
|
-
function createUploadHandler(configOrPlugin) {
|
|
7750
|
-
const plugin =
|
|
9498
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9499
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9500
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7751
9501
|
return async function POST(req) {
|
|
9502
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9503
|
+
if (authResult) return authResult;
|
|
7752
9504
|
try {
|
|
7753
9505
|
const formData = await req.formData();
|
|
7754
9506
|
const files = formData.getAll("files");
|
|
@@ -7822,6 +9574,190 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7822
9574
|
}
|
|
7823
9575
|
};
|
|
7824
9576
|
}
|
|
9577
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9578
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9579
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9580
|
+
return async function POST(req) {
|
|
9581
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9582
|
+
if (authResult) return authResult;
|
|
9583
|
+
try {
|
|
9584
|
+
const body = await req.json();
|
|
9585
|
+
const { query, namespace } = body;
|
|
9586
|
+
if (typeof query !== "string") {
|
|
9587
|
+
return NextResponse.json({ error: "query is required" }, { status: 400 });
|
|
9588
|
+
}
|
|
9589
|
+
const suggestions = await plugin.getSuggestions(query, namespace);
|
|
9590
|
+
return NextResponse.json({ suggestions });
|
|
9591
|
+
} catch (err) {
|
|
9592
|
+
const message = err instanceof Error ? err.message : "Internal server error";
|
|
9593
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9594
|
+
}
|
|
9595
|
+
};
|
|
9596
|
+
}
|
|
9597
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9598
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9599
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9600
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9601
|
+
return async function handler(req) {
|
|
9602
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9603
|
+
if (authResult) return authResult;
|
|
9604
|
+
const url = new URL(req.url);
|
|
9605
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9606
|
+
if (req.method === "GET") {
|
|
9607
|
+
try {
|
|
9608
|
+
const history = await storage.getHistory(sessionId);
|
|
9609
|
+
return NextResponse.json({ history });
|
|
9610
|
+
} catch (err) {
|
|
9611
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9612
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9613
|
+
}
|
|
9614
|
+
} else if (req.method === "POST") {
|
|
9615
|
+
try {
|
|
9616
|
+
const body = await req.json().catch(() => ({}));
|
|
9617
|
+
const sid = body.sessionId || sessionId;
|
|
9618
|
+
await storage.clearHistory(sid);
|
|
9619
|
+
return NextResponse.json({ success: true });
|
|
9620
|
+
} catch (err) {
|
|
9621
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9622
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9623
|
+
}
|
|
9624
|
+
}
|
|
9625
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9626
|
+
};
|
|
9627
|
+
}
|
|
9628
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9629
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9630
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9631
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9632
|
+
return async function handler(req) {
|
|
9633
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9634
|
+
if (authResult) return authResult;
|
|
9635
|
+
if (req.method === "GET") {
|
|
9636
|
+
try {
|
|
9637
|
+
const url = new URL(req.url);
|
|
9638
|
+
const messageId = url.searchParams.get("messageId");
|
|
9639
|
+
if (!messageId) {
|
|
9640
|
+
const feedbackList = await storage.listFeedback();
|
|
9641
|
+
return NextResponse.json({ feedback: feedbackList });
|
|
9642
|
+
}
|
|
9643
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9644
|
+
return NextResponse.json({ feedback });
|
|
9645
|
+
} catch (err) {
|
|
9646
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9647
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9648
|
+
}
|
|
9649
|
+
} else if (req.method === "POST") {
|
|
9650
|
+
try {
|
|
9651
|
+
const body = await req.json();
|
|
9652
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9653
|
+
if (!messageId) {
|
|
9654
|
+
return NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9655
|
+
}
|
|
9656
|
+
if (!rating) {
|
|
9657
|
+
return NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9658
|
+
}
|
|
9659
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9660
|
+
return NextResponse.json({ success: true });
|
|
9661
|
+
} catch (err) {
|
|
9662
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9663
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9664
|
+
}
|
|
9665
|
+
}
|
|
9666
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9667
|
+
};
|
|
9668
|
+
}
|
|
9669
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9670
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9671
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9672
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9673
|
+
return async function GET(req) {
|
|
9674
|
+
if (req) {
|
|
9675
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9676
|
+
if (authResult) return authResult;
|
|
9677
|
+
}
|
|
9678
|
+
void req;
|
|
9679
|
+
try {
|
|
9680
|
+
const sessions = await storage.listSessions();
|
|
9681
|
+
return NextResponse.json({ sessions });
|
|
9682
|
+
} catch (err) {
|
|
9683
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9684
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9685
|
+
}
|
|
9686
|
+
};
|
|
9687
|
+
}
|
|
9688
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9689
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9690
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9691
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9692
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9693
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9694
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9695
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9696
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9697
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9698
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
9699
|
+
async function routePostRequest(req, segment) {
|
|
9700
|
+
switch (segment) {
|
|
9701
|
+
case "chat":
|
|
9702
|
+
return streamHandler(req);
|
|
9703
|
+
case "chat-sync":
|
|
9704
|
+
return chatHandler(req);
|
|
9705
|
+
case "upload":
|
|
9706
|
+
return uploadHandler(req);
|
|
9707
|
+
case "suggestions":
|
|
9708
|
+
return suggestionsHandler(req);
|
|
9709
|
+
case "health":
|
|
9710
|
+
return healthHandler(req);
|
|
9711
|
+
case "history":
|
|
9712
|
+
case "history/clear":
|
|
9713
|
+
return historyHandler(req);
|
|
9714
|
+
case "feedback":
|
|
9715
|
+
return feedbackHandler(req);
|
|
9716
|
+
default:
|
|
9717
|
+
return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
9718
|
+
}
|
|
9719
|
+
}
|
|
9720
|
+
async function routeGetRequest(req, segment) {
|
|
9721
|
+
switch (segment) {
|
|
9722
|
+
case "health":
|
|
9723
|
+
return healthHandler(req);
|
|
9724
|
+
case "history":
|
|
9725
|
+
return historyHandler(req);
|
|
9726
|
+
case "feedback":
|
|
9727
|
+
return feedbackHandler(req);
|
|
9728
|
+
case "sessions":
|
|
9729
|
+
return sessionsHandler(req);
|
|
9730
|
+
default:
|
|
9731
|
+
return NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
9732
|
+
}
|
|
9733
|
+
}
|
|
9734
|
+
async function getSegment(context) {
|
|
9735
|
+
var _a2;
|
|
9736
|
+
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;
|
|
9737
|
+
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
9738
|
+
return segments.join("/") || "chat";
|
|
9739
|
+
}
|
|
9740
|
+
return {
|
|
9741
|
+
GET: async (req, context) => {
|
|
9742
|
+
try {
|
|
9743
|
+
const segment = await getSegment(context);
|
|
9744
|
+
return await routeGetRequest(req, segment);
|
|
9745
|
+
} catch (err) {
|
|
9746
|
+
const msg = err instanceof Error ? err.message : "GET Routing failed";
|
|
9747
|
+
return NextResponse.json({ error: msg }, { status: 500 });
|
|
9748
|
+
}
|
|
9749
|
+
},
|
|
9750
|
+
POST: async (req, context) => {
|
|
9751
|
+
try {
|
|
9752
|
+
const segment = await getSegment(context);
|
|
9753
|
+
return await routePostRequest(req, segment);
|
|
9754
|
+
} catch (err) {
|
|
9755
|
+
const msg = err instanceof Error ? err.message : "POST Routing failed";
|
|
9756
|
+
return NextResponse.json({ error: msg }, { status: 500 });
|
|
9757
|
+
}
|
|
9758
|
+
}
|
|
9759
|
+
};
|
|
9760
|
+
}
|
|
7825
9761
|
export {
|
|
7826
9762
|
AnthropicProvider,
|
|
7827
9763
|
AuthenticationException,
|
|
@@ -7837,8 +9773,10 @@ export {
|
|
|
7837
9773
|
EmbeddingFailedException,
|
|
7838
9774
|
EmbeddingStrategy,
|
|
7839
9775
|
EmbeddingStrategyResolver,
|
|
9776
|
+
GroqProvider,
|
|
7840
9777
|
LLMFactory,
|
|
7841
9778
|
LLM_PROFILES,
|
|
9779
|
+
LicenseVerifier,
|
|
7842
9780
|
MilvusProvider,
|
|
7843
9781
|
MongoDBProvider,
|
|
7844
9782
|
MultiTablePostgresProvider,
|
|
@@ -7852,6 +9790,7 @@ export {
|
|
|
7852
9790
|
ProviderNotFoundException,
|
|
7853
9791
|
ProviderRegistry,
|
|
7854
9792
|
QdrantProvider,
|
|
9793
|
+
QwenProvider,
|
|
7855
9794
|
RateLimitException,
|
|
7856
9795
|
RedisProvider,
|
|
7857
9796
|
RetrievalException,
|
|
@@ -7863,14 +9802,19 @@ export {
|
|
|
7863
9802
|
VectorPlugin,
|
|
7864
9803
|
WeaviateProvider,
|
|
7865
9804
|
createChatHandler,
|
|
9805
|
+
createFeedbackHandler,
|
|
7866
9806
|
createFromPreset,
|
|
7867
9807
|
createHealthHandler,
|
|
9808
|
+
createHistoryHandler,
|
|
7868
9809
|
createIngestHandler,
|
|
9810
|
+
createRagHandler,
|
|
9811
|
+
createSessionsHandler,
|
|
7869
9812
|
createStreamHandler,
|
|
7870
9813
|
createUploadHandler,
|
|
7871
9814
|
getRagConfig,
|
|
7872
9815
|
sseErrorFrame,
|
|
7873
9816
|
sseFrame,
|
|
7874
9817
|
sseMetaFrame,
|
|
7875
|
-
sseTextFrame
|
|
9818
|
+
sseTextFrame,
|
|
9819
|
+
wrapError
|
|
7876
9820
|
};
|