@retrivora-ai/rag-engine 1.9.7 → 1.9.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +127 -135
  2. package/dist/{ILLMProvider-Bhk6zJOK.d.mts → ILLMProvider-B8ROITYK.d.mts} +57 -2
  3. package/dist/{ILLMProvider-Bhk6zJOK.d.ts → ILLMProvider-B8ROITYK.d.ts} +57 -2
  4. package/dist/handlers/index.d.mts +2 -2
  5. package/dist/handlers/index.d.ts +2 -2
  6. package/dist/handlers/index.js +2198 -457
  7. package/dist/handlers/index.mjs +2195 -457
  8. package/dist/{index-BJ4cd-t5.d.mts → index-B8PbEFSY.d.mts} +12 -2
  9. package/dist/{index-Bu7T6xgr.d.ts → index-BCPKUAVL.d.ts} +27 -52
  10. package/dist/{index-C3SVtPYg.d.mts → index-CrxCy36A.d.mts} +27 -52
  11. package/dist/{index-B9J_XEh0.d.ts → index-DNvoi-sV.d.ts} +12 -2
  12. package/dist/index.css +578 -273
  13. package/dist/index.d.mts +29 -7
  14. package/dist/index.d.ts +29 -7
  15. package/dist/index.js +1160 -282
  16. package/dist/index.mjs +1185 -292
  17. package/dist/server.d.mts +62 -6
  18. package/dist/server.d.ts +62 -6
  19. package/dist/server.js +2061 -306
  20. package/dist/server.mjs +2055 -306
  21. package/package.json +11 -7
  22. package/src/app/constants.tsx +37 -7
  23. package/src/components/AmbientBackground.tsx +10 -10
  24. package/src/components/ArchitectureCard.tsx +43 -7
  25. package/src/components/ArchitectureCardsSection.tsx +37 -4
  26. package/src/components/ChatWidget.tsx +2 -1
  27. package/src/components/ChatWindow.tsx +4 -1
  28. package/src/components/CodeViewer.tsx +19 -14
  29. package/src/components/DocViewer.tsx +43 -49
  30. package/src/components/Documentation.tsx +71 -51
  31. package/src/components/Hero.tsx +103 -20
  32. package/src/components/Lifecycle.tsx +65 -25
  33. package/src/components/MarkdownComponents.tsx +44 -1
  34. package/src/components/MessageBubble.tsx +162 -50
  35. package/src/components/constants.tsx +4 -0
  36. package/src/config/RagConfig.ts +46 -0
  37. package/src/config/constants.ts +4 -0
  38. package/src/config/serverConfig.ts +15 -0
  39. package/src/core/ConfigResolver.ts +6 -0
  40. package/src/core/DatabaseStorage.ts +469 -0
  41. package/src/core/LicenseVerifier.ts +154 -0
  42. package/src/core/MultiAgentCoordinator.ts +239 -0
  43. package/src/core/Pipeline.ts +146 -15
  44. package/src/core/Retrivora.ts +6 -0
  45. package/src/core/VectorPlugin.ts +12 -3
  46. package/src/core/mcp.ts +261 -0
  47. package/src/handlers/index.ts +449 -63
  48. package/src/hooks/useRagChat.ts +96 -42
  49. package/src/hooks/useStoredMessages.ts +15 -4
  50. package/src/index.ts +5 -0
  51. package/src/llm/LLMFactory.ts +9 -1
  52. package/src/llm/providers/GroqProvider.ts +176 -0
  53. package/src/llm/providers/QwenProvider.ts +191 -0
  54. package/src/server.ts +7 -0
  55. package/src/types/chat.ts +14 -0
  56. package/src/types/props.ts +12 -0
  57. package/.env.example +0 -80
  58. package/LICENSE.txt +0 -21
@@ -80,9 +80,9 @@ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")])
80
80
  function isRecord(value) {
81
81
  return typeof value === "object" && value !== null;
82
82
  }
83
- function resolvePath(obj, path) {
84
- if (!path || !obj) return void 0;
85
- return path.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
83
+ function resolvePath(obj, path2) {
84
+ if (!path2 || !obj) return void 0;
85
+ return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
86
86
  if (!isRecord(current) && !Array.isArray(current)) {
87
87
  return void 0;
88
88
  }
@@ -192,7 +192,7 @@ var init_PineconeProvider = __esm({
192
192
  static getHealthChecker() {
193
193
  return {
194
194
  async check(config) {
195
- var _a, _b;
195
+ var _a2, _b;
196
196
  const opts = config.options || {};
197
197
  const indexName = config.indexName;
198
198
  const timestamp = Date.now();
@@ -200,7 +200,7 @@ var init_PineconeProvider = __esm({
200
200
  const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
201
201
  const client = new Pinecone2({ apiKey: opts.apiKey });
202
202
  const indexes = await client.listIndexes();
203
- const indexNames = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
203
+ const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
204
204
  if (!indexNames.includes(indexName)) {
205
205
  return {
206
206
  healthy: false,
@@ -227,10 +227,10 @@ var init_PineconeProvider = __esm({
227
227
  };
228
228
  }
229
229
  async initialize() {
230
- var _a, _b;
230
+ var _a2, _b;
231
231
  this.client = new import_pinecone.Pinecone({ apiKey: this.apiKey });
232
232
  const indexes = await this.client.listIndexes();
233
- const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
233
+ const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
234
234
  if (!names.includes(this.indexName)) {
235
235
  throw new Error(
236
236
  `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
@@ -242,12 +242,12 @@ var init_PineconeProvider = __esm({
242
242
  return namespace ? idx.namespace(namespace) : idx.namespace("");
243
243
  }
244
244
  async upsert(doc, namespace) {
245
- var _a;
245
+ var _a2;
246
246
  await this.index(namespace).upsert({
247
247
  records: [{
248
248
  id: String(doc.id),
249
249
  values: doc.vector,
250
- metadata: __spreadValues({ content: doc.content }, (_a = doc.metadata) != null ? _a : {})
250
+ metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
251
251
  }]
252
252
  });
253
253
  }
@@ -255,29 +255,29 @@ var init_PineconeProvider = __esm({
255
255
  const BATCH = 100;
256
256
  for (let i = 0; i < docs.length; i += BATCH) {
257
257
  const records = docs.slice(i, i + BATCH).map((d) => {
258
- var _a;
258
+ var _a2;
259
259
  return {
260
260
  id: String(d.id),
261
261
  values: d.vector,
262
- metadata: __spreadValues({ content: d.content }, (_a = d.metadata) != null ? _a : {})
262
+ metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
263
263
  };
264
264
  });
265
265
  await this.index(namespace).upsert({ records });
266
266
  }
267
267
  }
268
268
  async query(vector, topK, namespace, filter) {
269
- var _a;
269
+ var _a2;
270
270
  const pineconeFilter = this.sanitizeFilter(filter);
271
271
  const result = await this.index(namespace).query(__spreadValues({
272
272
  vector,
273
273
  topK,
274
274
  includeMetadata: true
275
275
  }, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
276
- return ((_a = result.matches) != null ? _a : []).map((m) => {
277
- var _a2, _b;
276
+ return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
277
+ var _a3, _b;
278
278
  return {
279
279
  id: m.id,
280
- score: (_a2 = m.score) != null ? _a2 : 0,
280
+ score: (_a3 = m.score) != null ? _a3 : 0,
281
281
  content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
282
282
  metadata: m.metadata
283
283
  };
@@ -316,13 +316,13 @@ var init_PostgreSQLProvider = __esm({
316
316
  init_BaseVectorProvider();
317
317
  PostgreSQLProvider = class extends BaseVectorProvider {
318
318
  constructor(config) {
319
- var _a;
319
+ var _a2;
320
320
  super(config);
321
321
  this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
322
322
  const opts = config.options;
323
323
  if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
324
324
  this.connectionString = opts.connectionString;
325
- this.dimensions = (_a = opts.dimensions) != null ? _a : 1536;
325
+ this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
326
326
  }
327
327
  static getValidator() {
328
328
  return {
@@ -403,7 +403,7 @@ var init_PostgreSQLProvider = __esm({
403
403
  }
404
404
  }
405
405
  async upsert(doc, namespace = "") {
406
- var _a;
406
+ var _a2;
407
407
  const vectorLiteral = `[${doc.vector.join(",")}]`;
408
408
  await this.pool.query(
409
409
  `INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
@@ -413,7 +413,7 @@ var init_PostgreSQLProvider = __esm({
413
413
  content = EXCLUDED.content,
414
414
  metadata = EXCLUDED.metadata,
415
415
  embedding = EXCLUDED.embedding`,
416
- [doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), vectorLiteral]
416
+ [doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
417
417
  );
418
418
  }
419
419
  async batchUpsert(docs, namespace = "") {
@@ -426,9 +426,9 @@ var init_PostgreSQLProvider = __esm({
426
426
  const batch = docs.slice(i, i + BATCH_SIZE);
427
427
  const values = [];
428
428
  const valuePlaceholders = batch.map((doc, idx) => {
429
- var _a;
429
+ var _a2;
430
430
  const offset = idx * 5;
431
- values.push(doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), `[${doc.vector.join(",")}]`);
431
+ values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
432
432
  return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
433
433
  }).join(", ");
434
434
  const query = `
@@ -511,8 +511,8 @@ var init_PostgreSQLProvider = __esm({
511
511
 
512
512
  // src/utils/synonyms.ts
513
513
  function resolveMetadataValue(meta, uiKey) {
514
- var _a;
515
- const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
514
+ var _a2;
515
+ const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
516
516
  const keys = Object.keys(meta);
517
517
  const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
518
518
  let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
@@ -599,14 +599,14 @@ var init_MultiTablePostgresProvider = __esm({
599
599
  init_synonyms();
600
600
  MultiTablePostgresProvider = class extends BaseVectorProvider {
601
601
  constructor(config) {
602
- var _a, _b, _c;
602
+ var _a2, _b, _c;
603
603
  super(config);
604
604
  const opts = config.options || {};
605
605
  if (!opts.connectionString) {
606
606
  throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
607
607
  }
608
608
  this.connectionString = opts.connectionString;
609
- this.dimensions = (_a = opts.dimensions) != null ? _a : 768;
609
+ this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
610
610
  this.tables = [];
611
611
  const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
612
612
  this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
@@ -664,11 +664,11 @@ var init_MultiTablePostgresProvider = __esm({
664
664
  * Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
665
665
  */
666
666
  async batchUpsert(docs, namespace = "") {
667
- var _a;
667
+ var _a2;
668
668
  if (docs.length === 0) return;
669
669
  const docsByFile = {};
670
670
  for (const doc of docs) {
671
- const fileName = ((_a = doc.metadata) == null ? void 0 : _a.fileName) || this.uploadTable;
671
+ const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
672
672
  if (!docsByFile[fileName]) docsByFile[fileName] = [];
673
673
  docsByFile[fileName].push(doc);
674
674
  }
@@ -721,11 +721,11 @@ var init_MultiTablePostgresProvider = __esm({
721
721
  const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
722
722
  const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
723
723
  const valuePlaceholders = batch.map((doc, idx) => {
724
- var _a2, _b;
724
+ var _a3, _b;
725
725
  const offset = idx * (5 + csvHeaders.length);
726
726
  values.push(doc.id);
727
727
  for (const h of csvHeaders) {
728
- values.push(String(((_a2 = doc.metadata) == null ? void 0 : _a2[h]) || ""));
728
+ values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
729
729
  }
730
730
  values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
731
731
  const docPlaceholders = [];
@@ -764,7 +764,7 @@ var init_MultiTablePostgresProvider = __esm({
764
764
  * Query all configured tables and merge results, sorted by cosine similarity score.
765
765
  */
766
766
  async query(vector, topK, _namespace, _filter) {
767
- var _a;
767
+ var _a2;
768
768
  if (!this.pool) {
769
769
  throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
770
770
  }
@@ -795,11 +795,11 @@ var init_MultiTablePostgresProvider = __esm({
795
795
  const filterParams = [];
796
796
  if (metadataFilters && Object.keys(metadataFilters).length > 0) {
797
797
  const conditions = Object.entries(metadataFilters).map(([key, val]) => {
798
- var _a3;
798
+ var _a4;
799
799
  filterParams.push(String(val));
800
800
  const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
801
801
  const paramIdx = baseOffset + filterParams.length;
802
- const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
802
+ const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
803
803
  const keysToCheck = [key, ...synonyms];
804
804
  const coalesceExprs = keysToCheck.flatMap((k) => [
805
805
  `metadata->>'${k}'`,
@@ -868,7 +868,7 @@ var init_MultiTablePostgresProvider = __esm({
868
868
  }
869
869
  const tableResults = [];
870
870
  for (const row of result.rows) {
871
- const _a2 = row, { hybrid_score, id } = _a2, rest = __objRest(_a2, ["hybrid_score", "id"]);
871
+ const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
872
872
  delete rest.embedding;
873
873
  delete rest.vector_score;
874
874
  delete rest.keyword_score;
@@ -897,10 +897,10 @@ var init_MultiTablePostgresProvider = __esm({
897
897
  }
898
898
  allResults.sort((a, b) => b.score - a.score);
899
899
  if (allResults.length === 0) return [];
900
- const bestMatchTable = (_a = allResults[0].metadata) == null ? void 0 : _a.source_table;
900
+ const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
901
901
  const finalSorted = allResults.filter((res) => {
902
- var _a2;
903
- return ((_a2 = res.metadata) == null ? void 0 : _a2.source_table) === bestMatchTable;
902
+ var _a3;
903
+ return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
904
904
  });
905
905
  console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
906
906
  console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
@@ -1305,14 +1305,14 @@ var init_QdrantProvider = __esm({
1305
1305
  * Samples points from the collection to discover available payload fields.
1306
1306
  */
1307
1307
  async discoverSchema() {
1308
- var _a;
1308
+ var _a2;
1309
1309
  try {
1310
1310
  const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
1311
1311
  limit: 20,
1312
1312
  with_payload: true,
1313
1313
  with_vector: false
1314
1314
  });
1315
- const points = ((_a = data.result) == null ? void 0 : _a.points) || [];
1315
+ const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
1316
1316
  const keys = /* @__PURE__ */ new Set();
1317
1317
  for (const point of points) {
1318
1318
  const payload = point.payload || {};
@@ -1338,12 +1338,12 @@ var init_QdrantProvider = __esm({
1338
1338
  * Ensures the collection exists. Creates it if missing.
1339
1339
  */
1340
1340
  async ensureCollection() {
1341
- var _a;
1341
+ var _a2;
1342
1342
  try {
1343
1343
  await this.http.get(`/collections/${this.indexName}`);
1344
1344
  console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
1345
1345
  } catch (err) {
1346
- if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
1346
+ if (import_axios4.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
1347
1347
  const opts = this.config.options;
1348
1348
  const dimensionsForCreate = opts.dimensions || 1536;
1349
1349
  console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
@@ -1363,7 +1363,7 @@ var init_QdrantProvider = __esm({
1363
1363
  * Ensures that a payload field has an index.
1364
1364
  */
1365
1365
  async ensureIndex(fieldName, schema = "keyword") {
1366
- var _a;
1366
+ var _a2;
1367
1367
  let fullPath = fieldName;
1368
1368
  if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
1369
1369
  fullPath = `${this.metadataField}.${fieldName}`;
@@ -1376,7 +1376,7 @@ var init_QdrantProvider = __esm({
1376
1376
  console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
1377
1377
  } catch (err) {
1378
1378
  let status;
1379
- if (import_axios4.default.isAxiosError(err)) status = (_a = err.response) == null ? void 0 : _a.status;
1379
+ if (import_axios4.default.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
1380
1380
  if (status === 409) return;
1381
1381
  console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
1382
1382
  }
@@ -1405,7 +1405,7 @@ var init_QdrantProvider = __esm({
1405
1405
  await this.http.put(`/collections/${this.indexName}/points`, payload);
1406
1406
  }
1407
1407
  async query(vector, topK, namespace, _filter) {
1408
- var _a;
1408
+ var _a2;
1409
1409
  const must = [];
1410
1410
  if (namespace) {
1411
1411
  must.push({ key: "namespace", match: { value: namespace } });
@@ -1427,7 +1427,7 @@ var init_QdrantProvider = __esm({
1427
1427
  limit: topK,
1428
1428
  with_payload: true,
1429
1429
  params: {
1430
- hnsw_ef: ((_a = this.config.options) == null ? void 0 : _a.efSearch) || Math.max(topK * 20, 128),
1430
+ hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
1431
1431
  exact: false
1432
1432
  },
1433
1433
  filter: must.length > 0 ? { must } : void 0
@@ -1522,13 +1522,13 @@ var init_ChromaDBProvider = __esm({
1522
1522
  * Get or create the ChromaDB collection.
1523
1523
  */
1524
1524
  async initialize() {
1525
- var _a;
1525
+ var _a2;
1526
1526
  try {
1527
1527
  const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
1528
1528
  this.collectionId = data.id;
1529
1529
  console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
1530
1530
  } catch (err) {
1531
- if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
1531
+ if (import_axios5.default.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
1532
1532
  console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
1533
1533
  const { data } = await this.http.post("/api/v1/collections", {
1534
1534
  name: this.indexName
@@ -1749,7 +1749,7 @@ var init_WeaviateProvider = __esm({
1749
1749
  await this.http.post("/v1/batch/objects", payload);
1750
1750
  }
1751
1751
  async query(vector, topK, namespace, _filter) {
1752
- var _a, _b;
1752
+ var _a2, _b;
1753
1753
  const queryText = _filter == null ? void 0 : _filter.queryText;
1754
1754
  const sanitizedFilter = this.sanitizeFilter(_filter);
1755
1755
  const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
@@ -1775,7 +1775,7 @@ var init_WeaviateProvider = __esm({
1775
1775
  `
1776
1776
  };
1777
1777
  const { data } = await this.http.post("/v1/graphql", graphqlQuery);
1778
- const results = ((_b = (_a = data.data) == null ? void 0 : _a.Get) == null ? void 0 : _b[this.indexName]) || [];
1778
+ const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
1779
1779
  return results.map((res) => ({
1780
1780
  id: res["_additional"].id,
1781
1781
  score: 1 - res["_additional"].distance,
@@ -1828,10 +1828,10 @@ var init_WeaviateProvider = __esm({
1828
1828
  return `{ operator: And, operands: [${operands.join(", ")}] }`;
1829
1829
  }
1830
1830
  weaviateOperand(key, value) {
1831
- const path = `path: [${JSON.stringify(key)}], operator: Equal`;
1832
- if (typeof value === "number") return `{ ${path}, valueNumber: ${value} }`;
1833
- if (typeof value === "boolean") return `{ ${path}, valueBoolean: ${value} }`;
1834
- return `{ ${path}, valueString: ${JSON.stringify(value)} }`;
1831
+ const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
1832
+ if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
1833
+ if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
1834
+ return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
1835
1835
  }
1836
1836
  };
1837
1837
  }
@@ -1858,21 +1858,21 @@ var init_UniversalVectorProvider = __esm({
1858
1858
  }
1859
1859
  }
1860
1860
  async initialize() {
1861
- var _a;
1861
+ var _a2;
1862
1862
  this.http = import_axios8.default.create({
1863
1863
  baseURL: this.opts.baseUrl,
1864
1864
  headers: __spreadValues({
1865
1865
  "Content-Type": "application/json"
1866
1866
  }, this.opts.headers),
1867
- timeout: (_a = this.opts.timeout) != null ? _a : 3e4
1867
+ timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
1868
1868
  });
1869
1869
  if (!await this.ping()) {
1870
1870
  throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
1871
1871
  }
1872
1872
  }
1873
1873
  async upsert(doc, namespace) {
1874
- var _a, _b, _c;
1875
- const endpoint = (_a = this.opts.upsertEndpoint) != null ? _a : "/upsert";
1874
+ var _a2, _b, _c;
1875
+ const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
1876
1876
  const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
1877
1877
  id: "{{id}}",
1878
1878
  vector: "{{vector}}",
@@ -1905,8 +1905,8 @@ var init_UniversalVectorProvider = __esm({
1905
1905
  }
1906
1906
  }
1907
1907
  async query(vector, topK, namespace, filter) {
1908
- var _a, _b;
1909
- const endpoint = (_a = this.opts.queryEndpoint) != null ? _a : "/query";
1908
+ var _a2, _b;
1909
+ const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
1910
1910
  const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
1911
1911
  vector: "{{vector}}",
1912
1912
  limit: "{{topK}}",
@@ -1932,12 +1932,12 @@ var init_UniversalVectorProvider = __esm({
1932
1932
  );
1933
1933
  }
1934
1934
  return results.map((item) => {
1935
- var _a2, _b2, _c, _d, _e, _f, _g;
1935
+ var _a3, _b2, _c, _d, _e, _f, _g2;
1936
1936
  return {
1937
- id: item[(_a2 = this.opts.queryIdField) != null ? _a2 : "id"],
1937
+ id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
1938
1938
  score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
1939
1939
  content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
1940
- metadata: (_g = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g : {}
1940
+ metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
1941
1941
  };
1942
1942
  });
1943
1943
  } catch (error) {
@@ -1947,8 +1947,8 @@ var init_UniversalVectorProvider = __esm({
1947
1947
  }
1948
1948
  }
1949
1949
  async delete(id, namespace) {
1950
- var _a, _b;
1951
- const endpoint = (_a = this.opts.deleteEndpoint) != null ? _a : "/delete";
1950
+ var _a2, _b;
1951
+ const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
1952
1952
  const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
1953
1953
  id: "{{id}}",
1954
1954
  namespace: "{{namespace}}"
@@ -1966,8 +1966,8 @@ var init_UniversalVectorProvider = __esm({
1966
1966
  }
1967
1967
  }
1968
1968
  async deleteNamespace(namespace) {
1969
- var _a;
1970
- const endpoint = (_a = this.opts.deleteNamespaceEndpoint) != null ? _a : "/delete-namespace";
1969
+ var _a2;
1970
+ const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
1971
1971
  try {
1972
1972
  await this.http.post(endpoint, { namespace });
1973
1973
  } catch (error) {
@@ -1977,9 +1977,9 @@ var init_UniversalVectorProvider = __esm({
1977
1977
  }
1978
1978
  }
1979
1979
  async ping() {
1980
- var _a;
1980
+ var _a2;
1981
1981
  try {
1982
- const endpoint = (_a = this.opts.pingEndpoint) != null ? _a : "/health";
1982
+ const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
1983
1983
  const response = await this.http.get(endpoint, { timeout: 5e3 });
1984
1984
  return response.status >= 200 && response.status < 300;
1985
1985
  } catch (e) {
@@ -2071,9 +2071,12 @@ var init_SimpleGraphProvider = __esm({
2071
2071
  var handlers_exports = {};
2072
2072
  __export(handlers_exports, {
2073
2073
  createChatHandler: () => createChatHandler,
2074
+ createFeedbackHandler: () => createFeedbackHandler,
2074
2075
  createHealthHandler: () => createHealthHandler,
2076
+ createHistoryHandler: () => createHistoryHandler,
2075
2077
  createIngestHandler: () => createIngestHandler,
2076
2078
  createRagHandler: () => createRagHandler,
2079
+ createSessionsHandler: () => createSessionsHandler,
2077
2080
  createStreamHandler: () => createStreamHandler,
2078
2081
  createSuggestionsHandler: () => createSuggestionsHandler,
2079
2082
  createUploadHandler: () => createUploadHandler,
@@ -2110,6 +2113,8 @@ var LLM_PROVIDERS = [
2110
2113
  "anthropic",
2111
2114
  "ollama",
2112
2115
  "gemini",
2116
+ "groq",
2117
+ "qwen",
2113
2118
  "rest",
2114
2119
  "universal_rest",
2115
2120
  "custom"
@@ -2118,6 +2123,7 @@ var EMBEDDING_PROVIDERS = [
2118
2123
  "openai",
2119
2124
  "ollama",
2120
2125
  "gemini",
2126
+ "qwen",
2121
2127
  "rest",
2122
2128
  "universal_rest",
2123
2129
  "custom"
@@ -2126,6 +2132,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
2126
2132
  "openai",
2127
2133
  "ollama",
2128
2134
  "gemini",
2135
+ "qwen",
2129
2136
  "rest",
2130
2137
  "universal_rest"
2131
2138
  ];
@@ -2133,8 +2140,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
2133
2140
 
2134
2141
  // src/config/serverConfig.ts
2135
2142
  function readString(env, name) {
2136
- var _a;
2137
- const value = (_a = env[name]) == null ? void 0 : _a.trim();
2143
+ var _a2;
2144
+ const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
2138
2145
  return value ? value : void 0;
2139
2146
  }
2140
2147
  function readNumber(env, name, fallback) {
@@ -2147,23 +2154,23 @@ function readNumber(env, name, fallback) {
2147
2154
  return parsed;
2148
2155
  }
2149
2156
  function readEnum(env, name, fallback, allowed) {
2150
- var _a;
2151
- const value = (_a = readString(env, name)) != null ? _a : fallback;
2157
+ var _a2;
2158
+ const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
2152
2159
  if (allowed.includes(value)) {
2153
2160
  return value;
2154
2161
  }
2155
2162
  throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
2156
2163
  }
2157
2164
  function getEnvConfig(env = process.env, base) {
2158
- var _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, _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;
2159
- const projectId = (_c = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
2165
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa;
2166
+ const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
2160
2167
  const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
2161
2168
  const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
2162
2169
  const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
2163
2170
  const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
2164
2171
  const vectorDbOptions = {};
2165
2172
  if (vectorProvider === "pinecone") {
2166
- vectorDbOptions.apiKey = (_g = (_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 ? _g : "";
2173
+ vectorDbOptions.apiKey = (_g2 = (_f = readString(env, "PINECONE_API_KEY")) != null ? _f : (_e = (_d = base == null ? void 0 : base.vectorDb) == null ? void 0 : _d.options) == null ? void 0 : _e.apiKey) != null ? _g2 : "";
2167
2174
  vectorDbOptions.indexName = (_l = (_i = readString(env, "PINECONE_INDEX")) != null ? _i : (_h = base == null ? void 0 : base.vectorDb) == null ? void 0 : _h.indexName) != null ? _l : (_k = (_j = base == null ? void 0 : base.vectorDb) == null ? void 0 : _j.options) == null ? void 0 : _k.indexName;
2168
2175
  } else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
2169
2176
  vectorDbOptions.connectionString = (_q = (_p = (_m = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _m : readString(env, "POSTGRES_URL")) != null ? _p : (_o = (_n = base == null ? void 0 : base.vectorDb) == null ? void 0 : _n.options) == null ? void 0 : _o.connectionString) != null ? _q : "";
@@ -2225,17 +2232,18 @@ function getEnvConfig(env = process.env, base) {
2225
2232
  rest: "default",
2226
2233
  custom: "default"
2227
2234
  };
2228
- return __spreadValues({
2235
+ return __spreadProps(__spreadValues({
2229
2236
  projectId,
2237
+ licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
2230
2238
  vectorDb: {
2231
2239
  provider: vectorProvider,
2232
- indexName: (_ha = (_ga = readString(env, "VECTOR_DB_INDEX")) != null ? _ga : vectorDbOptions.indexName) != null ? _ha : "rag-index",
2240
+ indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
2233
2241
  options: vectorDbOptions
2234
2242
  },
2235
2243
  llm: {
2236
2244
  provider: llmProvider,
2237
- model: (_ja = (_ia = readString(env, "LLM_MODEL")) != null ? _ia : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _ja : "gpt-4o",
2238
- apiKey: (_ka = llmApiKeyByProvider[llmProvider]) != null ? _ka : "",
2245
+ model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
2246
+ apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
2239
2247
  baseUrl: readString(env, "LLM_BASE_URL"),
2240
2248
  systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
2241
2249
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
@@ -2248,7 +2256,7 @@ function getEnvConfig(env = process.env, base) {
2248
2256
  },
2249
2257
  embedding: {
2250
2258
  provider: embeddingProvider,
2251
- model: (_la = readString(env, "EMBEDDING_MODEL")) != null ? _la : "text-embedding-3-small",
2259
+ model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
2252
2260
  apiKey: embeddingApiKeyByProvider[embeddingProvider],
2253
2261
  baseUrl: readString(env, "EMBEDDING_BASE_URL"),
2254
2262
  dimensions: embeddingDimensions,
@@ -2259,30 +2267,30 @@ function getEnvConfig(env = process.env, base) {
2259
2267
  }
2260
2268
  },
2261
2269
  ui: {
2262
- title: (_na = (_ma = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _ma : readString(env, "UI_TITLE")) != null ? _na : "AI Assistant",
2263
- subtitle: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _oa : readString(env, "UI_SUBTITLE")) != null ? _pa : "Powered by RAG",
2264
- primaryColor: (_ra = (_qa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _qa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ra : "#10b981",
2265
- accentColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _sa : readString(env, "UI_ACCENT_COLOR")) != null ? _ta : "#3b82f6",
2266
- logoUrl: (_ua = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _ua : readString(env, "UI_LOGO_URL"),
2267
- placeholder: (_wa = (_va = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _va : readString(env, "UI_PLACEHOLDER")) != null ? _wa : "Ask me anything\u2026",
2268
- showSources: ((_ya = (_xa = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _xa : readString(env, "UI_SHOW_SOURCES")) != null ? _ya : "true") !== "false",
2269
- welcomeMessage: (_Aa = (_za = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _za : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Aa : "Hello! I'm your AI assistant. Ask me anything about your documents.",
2270
- visualStyle: (_Ca = (_Ba = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Ba : readString(env, "UI_VISUAL_STYLE")) != null ? _Ca : "glass",
2271
- borderRadius: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Da : readString(env, "UI_BORDER_RADIUS")) != null ? _Ea : "xl",
2272
- allowUpload: ((_Ga = (_Fa = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Fa : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ga : "false") === "true"
2270
+ title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
2271
+ subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
2272
+ primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
2273
+ accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
2274
+ logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
2275
+ placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
2276
+ showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
2277
+ welcomeMessage: (_Ca = (_Ba = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _Ba : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Ca : "Hello! I'm your AI assistant. Ask me anything about your documents.",
2278
+ visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
2279
+ borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
2280
+ allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
2273
2281
  },
2274
2282
  rag: {
2275
2283
  topK: readNumber(env, "RAG_TOP_K", 5),
2276
2284
  scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
2277
2285
  chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
2278
2286
  chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
2279
- filterableFields: (_Ha = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ha.split(",").map((f) => f.trim()),
2287
+ filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
2280
2288
  // Query pipeline toggles — read from .env.local
2281
2289
  useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
2282
2290
  useReranking: readString(env, "RAG_USE_RERANKING") === "true",
2283
2291
  useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
2284
- architecture: (_Ia = readString(env, "RAG_ARCHITECTURE")) != null ? _Ia : "simple",
2285
- chunkingStrategy: (_Ja = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _Ja : "recursive",
2292
+ architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
2293
+ chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
2286
2294
  uiMapping: (() => {
2287
2295
  const raw = readString(env, "RAG_UI_MAPPING");
2288
2296
  if (!raw) return void 0;
@@ -2292,6 +2300,10 @@ function getEnvConfig(env = process.env, base) {
2292
2300
  return void 0;
2293
2301
  }
2294
2302
  })()
2303
+ },
2304
+ telemetry: {
2305
+ enabled: readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_Ma = base == null ? void 0 : base.telemetry) == null ? void 0 : _Ma.enabled) || false,
2306
+ url: (_Qa = (_Pa = (_Na = readString(env, "TELEMETRY_URL")) != null ? _Na : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _Pa : (_Oa = base == null ? void 0 : base.telemetry) == null ? void 0 : _Oa.url) != null ? _Qa : "/api/telemetry"
2295
2307
  }
2296
2308
  }, readString(env, "GRAPH_DB_PROVIDER") ? {
2297
2309
  graphDb: {
@@ -2302,7 +2314,19 @@ function getEnvConfig(env = process.env, base) {
2302
2314
  password: readString(env, "GRAPH_DB_PASSWORD")
2303
2315
  }
2304
2316
  }
2305
- } : {});
2317
+ } : {}), {
2318
+ mcpServers: (() => {
2319
+ var _a3;
2320
+ const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
2321
+ if (!raw) return void 0;
2322
+ try {
2323
+ return JSON.parse(raw);
2324
+ } catch (e) {
2325
+ console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
2326
+ return void 0;
2327
+ }
2328
+ })()
2329
+ });
2306
2330
  }
2307
2331
 
2308
2332
  // src/core/ConfigResolver.ts
@@ -2328,7 +2352,8 @@ var ConfigResolver = class {
2328
2352
  options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
2329
2353
  }) : envConfig.embedding,
2330
2354
  ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
2331
- rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
2355
+ rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
2356
+ telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
2332
2357
  });
2333
2358
  }
2334
2359
  /**
@@ -2337,10 +2362,10 @@ var ConfigResolver = class {
2337
2362
  * fallback behavior.
2338
2363
  */
2339
2364
  static resolveUniversal(hostConfig, env = process.env) {
2340
- var _a;
2365
+ var _a2;
2341
2366
  if (!hostConfig) return this.resolve(void 0, env);
2342
2367
  const normalized = __spreadProps(__spreadValues({}, hostConfig), {
2343
- vectorDb: (_a = hostConfig.vectorDb) != null ? _a : hostConfig.vectorDatabase,
2368
+ vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
2344
2369
  rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
2345
2370
  });
2346
2371
  return this.resolve(normalized, env);
@@ -2360,11 +2385,11 @@ var ConfigResolver = class {
2360
2385
  }
2361
2386
  }
2362
2387
  static mergeRetrievalWorkflow(rag, retrieval, workflow) {
2363
- var _a, _b, _c, _d, _e;
2388
+ var _a2, _b, _c, _d, _e;
2364
2389
  if (!rag && !retrieval && !workflow) return void 0;
2365
2390
  const normalized = __spreadValues({}, rag != null ? rag : {});
2366
2391
  if (retrieval) {
2367
- normalized.topK = (_a = retrieval.topK) != null ? _a : normalized.topK;
2392
+ normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
2368
2393
  normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
2369
2394
  normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
2370
2395
  if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
@@ -2446,8 +2471,8 @@ var OpenAIProvider = class {
2446
2471
  const apiKey = config.apiKey;
2447
2472
  const modelName = config.model;
2448
2473
  try {
2449
- const OpenAI2 = await import("openai");
2450
- const client = new OpenAI2.default({ apiKey });
2474
+ const OpenAI4 = await import("openai");
2475
+ const client = new OpenAI4.default({ apiKey });
2451
2476
  const models = await client.models.list();
2452
2477
  const hasModel = models.data.some((m) => m.id === modelName);
2453
2478
  return {
@@ -2468,8 +2493,8 @@ var OpenAIProvider = class {
2468
2493
  };
2469
2494
  }
2470
2495
  async chat(messages, context, options) {
2471
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2472
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2496
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
2497
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2473
2498
  const systemMessage = {
2474
2499
  role: "system",
2475
2500
  content: buildSystemContent(basePrompt, context)
@@ -2488,12 +2513,12 @@ var OpenAIProvider = class {
2488
2513
  temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
2489
2514
  stop: options == null ? void 0 : options.stop
2490
2515
  });
2491
- return (_i = (_h = (_g = completion.choices[0]) == null ? void 0 : _g.message) == null ? void 0 : _h.content) != null ? _i : "";
2516
+ return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
2492
2517
  }
2493
2518
  chatStream(messages, context, options) {
2494
2519
  return __asyncGenerator(this, null, function* () {
2495
- var _a, _b, _c, _d, _e, _f, _g, _h;
2496
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2520
+ var _a2, _b, _c, _d, _e, _f, _g2, _h;
2521
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
2497
2522
  const systemMessage = {
2498
2523
  role: "system",
2499
2524
  content: buildSystemContent(basePrompt, context)
@@ -2519,7 +2544,7 @@ var OpenAIProvider = class {
2519
2544
  try {
2520
2545
  for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2521
2546
  const chunk = temp.value;
2522
- const content = ((_h = (_g = chunk.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content) || "";
2547
+ const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
2523
2548
  if (content) yield content;
2524
2549
  }
2525
2550
  } catch (temp) {
@@ -2539,8 +2564,8 @@ var OpenAIProvider = class {
2539
2564
  return results[0];
2540
2565
  }
2541
2566
  async batchEmbed(texts, options) {
2542
- var _a, _b, _c, _d, _e;
2543
- const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-3-small";
2567
+ var _a2, _b, _c, _d, _e;
2568
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-3-small";
2544
2569
  const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
2545
2570
  const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
2546
2571
  const response = await client.embeddings.create({ model, input: texts });
@@ -2617,8 +2642,8 @@ var AnthropicProvider = class {
2617
2642
  };
2618
2643
  }
2619
2644
  async chat(messages, context, options) {
2620
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2621
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2645
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
2646
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2622
2647
  const system = buildSystemContent(basePrompt, context);
2623
2648
  const anthropicMessages = messages.map((m) => ({
2624
2649
  role: m.role === "assistant" ? "assistant" : "user",
@@ -2629,7 +2654,7 @@ var AnthropicProvider = class {
2629
2654
  const extraParams = {};
2630
2655
  if (isThinkingEnabled && isClaude37) {
2631
2656
  extraParams.betas = ["interleaved-thinking-2025-05-14"];
2632
- const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
2657
+ const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
2633
2658
  const budget = Math.min(
2634
2659
  typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
2635
2660
  maxTokens - 1
@@ -2656,8 +2681,8 @@ var AnthropicProvider = class {
2656
2681
  }
2657
2682
  chatStream(messages, context, options) {
2658
2683
  return __asyncGenerator(this, null, function* () {
2659
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2660
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2684
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
2685
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
2661
2686
  const system = buildSystemContent(basePrompt, context);
2662
2687
  const anthropicMessages = messages.map((m) => ({
2663
2688
  role: m.role === "assistant" ? "assistant" : "user",
@@ -2668,7 +2693,7 @@ var AnthropicProvider = class {
2668
2693
  const extraParams = {};
2669
2694
  if (isThinkingEnabled && isClaude37) {
2670
2695
  extraParams.betas = ["interleaved-thinking-2025-05-14"];
2671
- const maxTokens = (_g = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g : 4096;
2696
+ const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
2672
2697
  const budget = Math.min(
2673
2698
  typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
2674
2699
  maxTokens - 1
@@ -2741,8 +2766,8 @@ var AnthropicProvider = class {
2741
2766
  var import_axios = __toESM(require("axios"));
2742
2767
  var OllamaProvider = class {
2743
2768
  constructor(llmConfig, embeddingConfig) {
2744
- var _a, _b;
2745
- const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
2769
+ var _a2, _b;
2770
+ const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
2746
2771
  const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
2747
2772
  this.http = import_axios.default.create({ baseURL, timeout });
2748
2773
  this.llmConfig = llmConfig;
@@ -2800,8 +2825,8 @@ var OllamaProvider = class {
2800
2825
  };
2801
2826
  }
2802
2827
  async chat(messages, context, options) {
2803
- var _a, _b, _c, _d, _e, _f;
2804
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2828
+ var _a2, _b, _c, _d, _e, _f;
2829
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2805
2830
  const system = buildSystemContent(basePrompt, context);
2806
2831
  const { data } = await this.http.post("/api/chat", {
2807
2832
  model: this.llmConfig.model,
@@ -2819,8 +2844,8 @@ var OllamaProvider = class {
2819
2844
  }
2820
2845
  chatStream(messages, context, options) {
2821
2846
  return __asyncGenerator(this, null, function* () {
2822
- var _a, _b, _c, _d, _e, _f, _g, _h;
2823
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2847
+ var _a2, _b, _c, _d, _e, _f, _g2, _h;
2848
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
2824
2849
  const system = buildSystemContent(basePrompt, context);
2825
2850
  const response = yield new __await(this.http.post("/api/chat", {
2826
2851
  model: this.llmConfig.model,
@@ -2849,7 +2874,7 @@ var OllamaProvider = class {
2849
2874
  if (!line.trim()) continue;
2850
2875
  try {
2851
2876
  const json = JSON.parse(line);
2852
- if ((_g = json.message) == null ? void 0 : _g.content) {
2877
+ if ((_g2 = json.message) == null ? void 0 : _g2.content) {
2853
2878
  yield json.message.content;
2854
2879
  }
2855
2880
  if (json.done) return;
@@ -2878,10 +2903,10 @@ var OllamaProvider = class {
2878
2903
  });
2879
2904
  }
2880
2905
  async embed(text, options) {
2881
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
2882
- const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
2906
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
2907
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "nomic-embed-text";
2883
2908
  const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
2884
- const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
2909
+ const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
2885
2910
  let prompt = text;
2886
2911
  const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
2887
2912
  const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
@@ -2980,9 +3005,9 @@ var GeminiProvider = class {
2980
3005
  static getHealthChecker() {
2981
3006
  return {
2982
3007
  async check(config) {
2983
- var _a, _b;
3008
+ var _a2, _b;
2984
3009
  const timestamp = Date.now();
2985
- const apiKey = (_b = (_a = config.apiKey) != null ? _a : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
3010
+ const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
2986
3011
  const modelName = sanitizeModel(config.model);
2987
3012
  try {
2988
3013
  const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
@@ -3012,16 +3037,16 @@ var GeminiProvider = class {
3012
3037
  /** Resolve the embedding client — uses a separate client when the embedding
3013
3038
  * API key differs from the LLM API key. */
3014
3039
  get embeddingClient() {
3015
- var _a;
3016
- if (((_a = this.embeddingConfig) == null ? void 0 : _a.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
3040
+ var _a2;
3041
+ if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
3017
3042
  return buildClient(this.embeddingConfig.apiKey);
3018
3043
  }
3019
3044
  return this.client;
3020
3045
  }
3021
3046
  /** Resolve the embedding model to use, in order of specificity. */
3022
3047
  resolveEmbeddingModel(optionsModel) {
3023
- var _a, _b;
3024
- return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
3048
+ var _a2, _b;
3049
+ return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
3025
3050
  }
3026
3051
  /**
3027
3052
  * Convert ChatMessage[] to the Gemini contents format.
@@ -3041,8 +3066,8 @@ var GeminiProvider = class {
3041
3066
  // ILLMProvider — chat
3042
3067
  // -------------------------------------------------------------------------
3043
3068
  async chat(messages, context, options) {
3044
- var _a, _b, _c, _d, _e, _f;
3045
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3069
+ var _a2, _b, _c, _d, _e, _f;
3070
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3046
3071
  const model = this.client.getGenerativeModel({
3047
3072
  model: this.llmConfig.model,
3048
3073
  systemInstruction: buildSystemContent(basePrompt, context)
@@ -3059,8 +3084,8 @@ var GeminiProvider = class {
3059
3084
  }
3060
3085
  chatStream(messages, context, options) {
3061
3086
  return __asyncGenerator(this, null, function* () {
3062
- var _a, _b, _c, _d, _e, _f;
3063
- const basePrompt = (_b = (_a = options == null ? void 0 : options.systemPrompt) != null ? _a : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3087
+ var _a2, _b, _c, _d, _e, _f;
3088
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3064
3089
  const model = this.client.getGenerativeModel({
3065
3090
  model: this.llmConfig.model,
3066
3091
  systemInstruction: buildSystemContent(basePrompt, context)
@@ -3095,11 +3120,11 @@ var GeminiProvider = class {
3095
3120
  // ILLMProvider — embeddings
3096
3121
  // -------------------------------------------------------------------------
3097
3122
  async embed(text, options) {
3098
- var _a, _b;
3123
+ var _a2, _b;
3099
3124
  const content = applyPrefix(
3100
3125
  text,
3101
3126
  options == null ? void 0 : options.taskType,
3102
- (_a = this.embeddingConfig) == null ? void 0 : _a.queryPrefix,
3127
+ (_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
3103
3128
  (_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
3104
3129
  );
3105
3130
  const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
@@ -3116,7 +3141,7 @@ var GeminiProvider = class {
3116
3141
  const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
3117
3142
  const model = this.embeddingClient.getGenerativeModel({ model: modelName });
3118
3143
  const requests = texts.map((text) => {
3119
- var _a, _b;
3144
+ var _a2, _b;
3120
3145
  return {
3121
3146
  content: {
3122
3147
  role: "user",
@@ -3124,7 +3149,7 @@ var GeminiProvider = class {
3124
3149
  text: applyPrefix(
3125
3150
  text,
3126
3151
  options == null ? void 0 : options.taskType,
3127
- (_a = this.embeddingConfig) == null ? void 0 : _a.queryPrefix,
3152
+ (_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
3128
3153
  (_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
3129
3154
  )
3130
3155
  }]
@@ -3141,8 +3166,8 @@ var GeminiProvider = class {
3141
3166
  throw err;
3142
3167
  });
3143
3168
  return response.embeddings.map((e) => {
3144
- var _a;
3145
- return (_a = e.values) != null ? _a : [];
3169
+ var _a2;
3170
+ return (_a2 = e.values) != null ? _a2 : [];
3146
3171
  });
3147
3172
  }
3148
3173
  // -------------------------------------------------------------------------
@@ -3162,192 +3187,511 @@ var GeminiProvider = class {
3162
3187
  }
3163
3188
  };
3164
3189
 
3165
- // src/llm/providers/UniversalLLMAdapter.ts
3166
- var import_axios2 = __toESM(require("axios"));
3167
- init_templateUtils();
3168
-
3169
- // src/config/UniversalProfiles.ts
3170
- var OPENAI_BASE = {
3171
- chatPath: "/chat/completions",
3172
- embedPath: "/embeddings",
3173
- responseExtractPath: "choices[0].message.content",
3174
- embedExtractPath: "data[0].embedding",
3175
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
3176
- };
3177
- var LLM_PROFILES = {
3178
- "openai-compatible": OPENAI_BASE,
3179
- "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
3180
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
3181
- }),
3182
- "anthropic-claude": {
3183
- chatPath: "/v1/messages",
3184
- responseExtractPath: "content[0].text",
3185
- headers: { "anthropic-version": "2023-06-01" },
3186
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
3187
- },
3188
- "google-gemini": {
3189
- chatPath: "/v1beta/models/{{model}}:generateContent",
3190
- responseExtractPath: "candidates[0].content.parts[0].text",
3191
- chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
3192
- },
3193
- "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
3194
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
3195
- }),
3196
- "ollama-standard": {
3197
- chatPath: "/api/chat",
3198
- embedPath: "/api/embeddings",
3199
- responseExtractPath: "message.content",
3200
- embedExtractPath: "embedding",
3201
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
3202
- embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
3203
- }
3204
- };
3205
-
3206
- // src/llm/providers/UniversalLLMAdapter.ts
3207
- var UniversalLLMAdapter = class {
3208
- constructor(config) {
3209
- var _a, _b, _c, _d, _e, _f, _g, _h;
3210
- this.model = config.model;
3211
- const llmConfig = config;
3212
- const options = (_a = llmConfig.options) != null ? _a : {};
3213
- let profile = {};
3214
- if (typeof options.profile === "string") {
3215
- profile = LLM_PROFILES[options.profile] || {};
3216
- } else if (typeof options.profile === "object" && options.profile !== null) {
3217
- profile = options.profile;
3218
- }
3219
- this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
3220
- this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
3221
- this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
3222
- this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
3223
- this.apiKey = config.apiKey;
3224
- this.baseUrl = (_g = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g : "";
3225
- if (!this.baseUrl) {
3226
- throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
3227
- }
3228
- this.resolvedHeaders = __spreadValues(__spreadValues({
3229
- "Content-Type": "application/json"
3230
- }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
3231
- this.http = import_axios2.default.create({
3232
- baseURL: this.baseUrl,
3233
- headers: this.resolvedHeaders,
3234
- timeout: (_h = this.opts.timeout) != null ? _h : 6e4
3190
+ // src/llm/providers/GroqProvider.ts
3191
+ var import_openai2 = __toESM(require("openai"));
3192
+ var GroqProvider = class {
3193
+ constructor(llmConfig, embeddingConfig) {
3194
+ void embeddingConfig;
3195
+ const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
3196
+ if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
3197
+ this.client = new import_openai2.default({
3198
+ apiKey,
3199
+ baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
3235
3200
  });
3201
+ this.llmConfig = llmConfig;
3236
3202
  }
3237
- async chat(messages, context) {
3238
- var _a, _b;
3239
- const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
3203
+ static getValidator() {
3204
+ return {
3205
+ validate(config) {
3206
+ const errors = [];
3207
+ if (!config.apiKey && !process.env.GROQ_API_KEY) {
3208
+ errors.push({
3209
+ field: "llm.apiKey",
3210
+ message: "Groq API key is required",
3211
+ suggestion: "Set GROQ_API_KEY environment variable",
3212
+ severity: "error"
3213
+ });
3214
+ }
3215
+ if (!config.model) {
3216
+ errors.push({
3217
+ field: "llm.model",
3218
+ message: "Groq model name is required",
3219
+ suggestion: 'e.g., "llama-3.3-70b-versatile"',
3220
+ severity: "error"
3221
+ });
3222
+ }
3223
+ return errors;
3224
+ }
3225
+ };
3226
+ }
3227
+ static getHealthChecker() {
3228
+ return {
3229
+ async check(config) {
3230
+ const timestamp = Date.now();
3231
+ const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
3232
+ const modelName = config.model;
3233
+ try {
3234
+ const OpenAI4 = await import("openai");
3235
+ const client = new OpenAI4.default({
3236
+ apiKey,
3237
+ baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
3238
+ });
3239
+ const models = await client.models.list();
3240
+ const hasModel = models.data.some((m) => m.id === modelName);
3241
+ return {
3242
+ healthy: true,
3243
+ provider: "groq",
3244
+ capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
3245
+ timestamp
3246
+ };
3247
+ } catch (error) {
3248
+ return {
3249
+ healthy: false,
3250
+ provider: "groq",
3251
+ error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
3252
+ timestamp
3253
+ };
3254
+ }
3255
+ }
3256
+ };
3257
+ }
3258
+ async chat(messages, context, options) {
3259
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
3260
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3261
+ const systemMessage = {
3262
+ role: "system",
3263
+ content: buildSystemContent(basePrompt, context)
3264
+ };
3240
3265
  const formattedMessages = [
3241
- { role: "system", content: `${this.systemPrompt}
3242
-
3243
- Context:
3244
- ${context != null ? context : "None"}` },
3245
- ...messages
3266
+ systemMessage,
3267
+ ...messages.map((m) => ({
3268
+ role: m.role,
3269
+ content: m.content
3270
+ }))
3246
3271
  ];
3247
- let payload;
3248
- if (this.opts.chatPayloadTemplate) {
3249
- payload = buildPayload(this.opts.chatPayloadTemplate, {
3250
- model: this.model,
3251
- messages: formattedMessages,
3252
- maxTokens: this.maxTokens,
3253
- temperature: this.temperature
3254
- });
3255
- } else {
3256
- payload = {
3257
- model: this.model,
3258
- messages: formattedMessages,
3259
- max_tokens: this.maxTokens,
3260
- temperature: this.temperature
3261
- };
3262
- }
3263
- const { data } = await this.http.post(path, payload);
3264
- const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
3265
- const result = resolvePath(data, extractPath);
3266
- if (result === void 0) {
3267
- throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
3268
- }
3269
- return String(result);
3272
+ const completion = await this.client.chat.completions.create({
3273
+ model: this.llmConfig.model,
3274
+ messages: formattedMessages,
3275
+ max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
3276
+ temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
3277
+ stop: options == null ? void 0 : options.stop
3278
+ });
3279
+ return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
3270
3280
  }
3271
- /**
3272
- * Streaming chat using native fetch + ReadableStream.
3273
- * Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
3274
- * Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
3275
- */
3276
- chatStream(messages, context) {
3281
+ chatStream(messages, context, options) {
3277
3282
  return __asyncGenerator(this, null, function* () {
3278
- var _a, _b, _c;
3279
- const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
3280
- const url = `${this.baseUrl.replace(/\/$/, "")}${path}`;
3281
- const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
3283
+ var _a2, _b, _c, _d, _e, _f, _g2, _h;
3284
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3285
+ const systemMessage = {
3286
+ role: "system",
3287
+ content: buildSystemContent(basePrompt, context)
3288
+ };
3282
3289
  const formattedMessages = [
3283
- { role: "system", content: `${this.systemPrompt}
3284
-
3285
- Context:
3286
- ${context != null ? context : "None"}` },
3287
- ...messages
3290
+ systemMessage,
3291
+ ...messages.map((m) => ({
3292
+ role: m.role,
3293
+ content: m.content
3294
+ }))
3288
3295
  ];
3289
- let payload;
3290
- if (this.opts.chatPayloadTemplate) {
3291
- payload = buildPayload(this.opts.chatPayloadTemplate, {
3292
- model: this.model,
3293
- messages: formattedMessages,
3294
- maxTokens: this.maxTokens,
3295
- temperature: this.temperature
3296
- });
3297
- if (typeof payload === "object" && payload !== null) {
3298
- payload.stream = true;
3299
- }
3300
- } else {
3301
- payload = {
3302
- model: this.model,
3303
- messages: formattedMessages,
3304
- max_tokens: this.maxTokens,
3305
- temperature: this.temperature,
3306
- stream: true
3307
- };
3308
- }
3309
- const response = yield new __await(fetch(url, {
3310
- method: "POST",
3311
- headers: this.resolvedHeaders,
3312
- body: JSON.stringify(payload)
3296
+ const stream = yield new __await(this.client.chat.completions.create({
3297
+ model: this.llmConfig.model,
3298
+ messages: formattedMessages,
3299
+ max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
3300
+ temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
3301
+ stop: options == null ? void 0 : options.stop,
3302
+ stream: true
3313
3303
  }));
3314
- if (!response.ok) {
3315
- const errorText = yield new __await(response.text().catch(() => response.statusText));
3316
- throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
3317
- }
3318
- if (!response.body) {
3319
- throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
3304
+ if (!stream) {
3305
+ throw new Error("[GroqProvider] completions.create stream is undefined");
3320
3306
  }
3321
- const reader = response.body.getReader();
3322
- const decoder = new TextDecoder("utf-8");
3323
- let buffer = "";
3324
3307
  try {
3325
- while (true) {
3326
- const { done, value } = yield new __await(reader.read());
3327
- if (done) break;
3328
- buffer += decoder.decode(value, { stream: true });
3329
- const lines = buffer.split("\n");
3330
- buffer = (_c = lines.pop()) != null ? _c : "";
3331
- for (const line of lines) {
3332
- const trimmed = line.trim();
3333
- if (!trimmed || trimmed === "data: [DONE]") continue;
3334
- if (!trimmed.startsWith("data:")) continue;
3335
- try {
3336
- const json = JSON.parse(trimmed.slice(5).trim());
3337
- const text = resolvePath(json, extractPath);
3338
- if (text && typeof text === "string") yield text;
3339
- } catch (e) {
3340
- }
3341
- }
3342
- }
3343
- if (buffer.trim() && buffer.trim() !== "data: [DONE]") {
3344
- const jsonStr = buffer.replace(/^data:\s*/, "").trim();
3345
- try {
3346
- const json = JSON.parse(jsonStr);
3347
- const text = resolvePath(json, extractPath);
3348
- if (text && typeof text === "string") yield text;
3349
- } catch (e) {
3350
- }
3308
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
3309
+ const chunk = temp.value;
3310
+ const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
3311
+ if (content) yield content;
3312
+ }
3313
+ } catch (temp) {
3314
+ error = [temp];
3315
+ } finally {
3316
+ try {
3317
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
3318
+ } finally {
3319
+ if (error)
3320
+ throw error[0];
3321
+ }
3322
+ }
3323
+ });
3324
+ }
3325
+ async embed(text, options) {
3326
+ void text;
3327
+ void options;
3328
+ throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
3329
+ }
3330
+ async batchEmbed(texts, options) {
3331
+ void texts;
3332
+ void options;
3333
+ throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
3334
+ }
3335
+ async ping() {
3336
+ try {
3337
+ await this.client.models.list();
3338
+ return true;
3339
+ } catch (err) {
3340
+ console.error("[GroqProvider] Ping failed:", err);
3341
+ return false;
3342
+ }
3343
+ }
3344
+ };
3345
+
3346
+ // src/llm/providers/QwenProvider.ts
3347
+ var import_openai3 = __toESM(require("openai"));
3348
+ var QwenProvider = class {
3349
+ constructor(llmConfig, embeddingConfig) {
3350
+ const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
3351
+ if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
3352
+ this.client = new import_openai3.default({
3353
+ apiKey,
3354
+ baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
3355
+ });
3356
+ this.llmConfig = llmConfig;
3357
+ this.embeddingConfig = embeddingConfig;
3358
+ }
3359
+ static getValidator() {
3360
+ return {
3361
+ validate(config) {
3362
+ const errors = [];
3363
+ const isEmbedding = config.provider === "qwen" && "dimensions" in config;
3364
+ const prefix = isEmbedding ? "embedding" : "llm";
3365
+ if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
3366
+ errors.push({
3367
+ field: `${prefix}.apiKey`,
3368
+ message: "Qwen API key is required",
3369
+ suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
3370
+ severity: "error"
3371
+ });
3372
+ }
3373
+ if (!config.model) {
3374
+ errors.push({
3375
+ field: `${prefix}.model`,
3376
+ message: "Qwen model name is required",
3377
+ suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
3378
+ severity: "error"
3379
+ });
3380
+ }
3381
+ return errors;
3382
+ }
3383
+ };
3384
+ }
3385
+ static getHealthChecker() {
3386
+ return {
3387
+ async check(config) {
3388
+ const timestamp = Date.now();
3389
+ const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
3390
+ const modelName = config.model;
3391
+ try {
3392
+ const OpenAI4 = await import("openai");
3393
+ const client = new OpenAI4.default({
3394
+ apiKey,
3395
+ baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
3396
+ });
3397
+ const models = await client.models.list();
3398
+ const hasModel = models.data.some((m) => m.id === modelName);
3399
+ return {
3400
+ healthy: true,
3401
+ provider: "qwen",
3402
+ capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
3403
+ timestamp
3404
+ };
3405
+ } catch (error) {
3406
+ return {
3407
+ healthy: false,
3408
+ provider: "qwen",
3409
+ error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
3410
+ timestamp
3411
+ };
3412
+ }
3413
+ }
3414
+ };
3415
+ }
3416
+ async chat(messages, context, options) {
3417
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
3418
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3419
+ const systemMessage = {
3420
+ role: "system",
3421
+ content: buildSystemContent(basePrompt, context)
3422
+ };
3423
+ const formattedMessages = [
3424
+ systemMessage,
3425
+ ...messages.map((m) => ({
3426
+ role: m.role,
3427
+ content: m.content
3428
+ }))
3429
+ ];
3430
+ const completion = await this.client.chat.completions.create({
3431
+ model: this.llmConfig.model,
3432
+ messages: formattedMessages,
3433
+ max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
3434
+ temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
3435
+ stop: options == null ? void 0 : options.stop
3436
+ });
3437
+ return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
3438
+ }
3439
+ chatStream(messages, context, options) {
3440
+ return __asyncGenerator(this, null, function* () {
3441
+ var _a2, _b, _c, _d, _e, _f, _g2, _h;
3442
+ const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
3443
+ const systemMessage = {
3444
+ role: "system",
3445
+ content: buildSystemContent(basePrompt, context)
3446
+ };
3447
+ const formattedMessages = [
3448
+ systemMessage,
3449
+ ...messages.map((m) => ({
3450
+ role: m.role,
3451
+ content: m.content
3452
+ }))
3453
+ ];
3454
+ const stream = yield new __await(this.client.chat.completions.create({
3455
+ model: this.llmConfig.model,
3456
+ messages: formattedMessages,
3457
+ max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
3458
+ temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
3459
+ stop: options == null ? void 0 : options.stop,
3460
+ stream: true
3461
+ }));
3462
+ if (!stream) {
3463
+ throw new Error("[QwenProvider] completions.create stream is undefined");
3464
+ }
3465
+ try {
3466
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
3467
+ const chunk = temp.value;
3468
+ const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
3469
+ if (content) yield content;
3470
+ }
3471
+ } catch (temp) {
3472
+ error = [temp];
3473
+ } finally {
3474
+ try {
3475
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
3476
+ } finally {
3477
+ if (error)
3478
+ throw error[0];
3479
+ }
3480
+ }
3481
+ });
3482
+ }
3483
+ async embed(text, options) {
3484
+ const results = await this.batchEmbed([text], options);
3485
+ return results[0];
3486
+ }
3487
+ async batchEmbed(texts, options) {
3488
+ var _a2, _b, _c, _d, _e, _f;
3489
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-v1";
3490
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
3491
+ const client = apiKey !== this.llmConfig.apiKey ? new import_openai3.default({
3492
+ apiKey,
3493
+ baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
3494
+ }) : this.client;
3495
+ const response = await client.embeddings.create({ model, input: texts });
3496
+ return response.data.map((d) => d.embedding);
3497
+ }
3498
+ async ping() {
3499
+ try {
3500
+ await this.client.models.list();
3501
+ return true;
3502
+ } catch (err) {
3503
+ console.error("[QwenProvider] Ping failed:", err);
3504
+ return false;
3505
+ }
3506
+ }
3507
+ };
3508
+
3509
+ // src/llm/providers/UniversalLLMAdapter.ts
3510
+ var import_axios2 = __toESM(require("axios"));
3511
+ init_templateUtils();
3512
+
3513
+ // src/config/UniversalProfiles.ts
3514
+ var OPENAI_BASE = {
3515
+ chatPath: "/chat/completions",
3516
+ embedPath: "/embeddings",
3517
+ responseExtractPath: "choices[0].message.content",
3518
+ embedExtractPath: "data[0].embedding",
3519
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
3520
+ };
3521
+ var LLM_PROFILES = {
3522
+ "openai-compatible": OPENAI_BASE,
3523
+ "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
3524
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
3525
+ }),
3526
+ "anthropic-claude": {
3527
+ chatPath: "/v1/messages",
3528
+ responseExtractPath: "content[0].text",
3529
+ headers: { "anthropic-version": "2023-06-01" },
3530
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
3531
+ },
3532
+ "google-gemini": {
3533
+ chatPath: "/v1beta/models/{{model}}:generateContent",
3534
+ responseExtractPath: "candidates[0].content.parts[0].text",
3535
+ chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
3536
+ },
3537
+ "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
3538
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
3539
+ }),
3540
+ "ollama-standard": {
3541
+ chatPath: "/api/chat",
3542
+ embedPath: "/api/embeddings",
3543
+ responseExtractPath: "message.content",
3544
+ embedExtractPath: "embedding",
3545
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
3546
+ embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
3547
+ }
3548
+ };
3549
+
3550
+ // src/llm/providers/UniversalLLMAdapter.ts
3551
+ var UniversalLLMAdapter = class {
3552
+ constructor(config) {
3553
+ var _a2, _b, _c, _d, _e, _f, _g2, _h;
3554
+ this.model = config.model;
3555
+ const llmConfig = config;
3556
+ const options = (_a2 = llmConfig.options) != null ? _a2 : {};
3557
+ let profile = {};
3558
+ if (typeof options.profile === "string") {
3559
+ profile = LLM_PROFILES[options.profile] || {};
3560
+ } else if (typeof options.profile === "object" && options.profile !== null) {
3561
+ profile = options.profile;
3562
+ }
3563
+ this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
3564
+ this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
3565
+ this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
3566
+ this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
3567
+ this.apiKey = config.apiKey;
3568
+ this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
3569
+ if (!this.baseUrl) {
3570
+ throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
3571
+ }
3572
+ this.resolvedHeaders = __spreadValues(__spreadValues({
3573
+ "Content-Type": "application/json"
3574
+ }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
3575
+ this.http = import_axios2.default.create({
3576
+ baseURL: this.baseUrl,
3577
+ headers: this.resolvedHeaders,
3578
+ timeout: (_h = this.opts.timeout) != null ? _h : 6e4
3579
+ });
3580
+ }
3581
+ async chat(messages, context) {
3582
+ var _a2, _b;
3583
+ const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
3584
+ const formattedMessages = [
3585
+ { role: "system", content: `${this.systemPrompt}
3586
+
3587
+ Context:
3588
+ ${context != null ? context : "None"}` },
3589
+ ...messages
3590
+ ];
3591
+ let payload;
3592
+ if (this.opts.chatPayloadTemplate) {
3593
+ payload = buildPayload(this.opts.chatPayloadTemplate, {
3594
+ model: this.model,
3595
+ messages: formattedMessages,
3596
+ maxTokens: this.maxTokens,
3597
+ temperature: this.temperature
3598
+ });
3599
+ } else {
3600
+ payload = {
3601
+ model: this.model,
3602
+ messages: formattedMessages,
3603
+ max_tokens: this.maxTokens,
3604
+ temperature: this.temperature
3605
+ };
3606
+ }
3607
+ const { data } = await this.http.post(path2, payload);
3608
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
3609
+ const result = resolvePath(data, extractPath);
3610
+ if (result === void 0) {
3611
+ throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
3612
+ }
3613
+ return String(result);
3614
+ }
3615
+ /**
3616
+ * Streaming chat using native fetch + ReadableStream.
3617
+ * Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
3618
+ * Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
3619
+ */
3620
+ chatStream(messages, context) {
3621
+ return __asyncGenerator(this, null, function* () {
3622
+ var _a2, _b, _c;
3623
+ const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
3624
+ const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
3625
+ const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
3626
+ const formattedMessages = [
3627
+ { role: "system", content: `${this.systemPrompt}
3628
+
3629
+ Context:
3630
+ ${context != null ? context : "None"}` },
3631
+ ...messages
3632
+ ];
3633
+ let payload;
3634
+ if (this.opts.chatPayloadTemplate) {
3635
+ payload = buildPayload(this.opts.chatPayloadTemplate, {
3636
+ model: this.model,
3637
+ messages: formattedMessages,
3638
+ maxTokens: this.maxTokens,
3639
+ temperature: this.temperature
3640
+ });
3641
+ if (typeof payload === "object" && payload !== null) {
3642
+ payload.stream = true;
3643
+ }
3644
+ } else {
3645
+ payload = {
3646
+ model: this.model,
3647
+ messages: formattedMessages,
3648
+ max_tokens: this.maxTokens,
3649
+ temperature: this.temperature,
3650
+ stream: true
3651
+ };
3652
+ }
3653
+ const response = yield new __await(fetch(url, {
3654
+ method: "POST",
3655
+ headers: this.resolvedHeaders,
3656
+ body: JSON.stringify(payload)
3657
+ }));
3658
+ if (!response.ok) {
3659
+ const errorText = yield new __await(response.text().catch(() => response.statusText));
3660
+ throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
3661
+ }
3662
+ if (!response.body) {
3663
+ throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
3664
+ }
3665
+ const reader = response.body.getReader();
3666
+ const decoder = new TextDecoder("utf-8");
3667
+ let buffer = "";
3668
+ try {
3669
+ while (true) {
3670
+ const { done, value } = yield new __await(reader.read());
3671
+ if (done) break;
3672
+ buffer += decoder.decode(value, { stream: true });
3673
+ const lines = buffer.split("\n");
3674
+ buffer = (_c = lines.pop()) != null ? _c : "";
3675
+ for (const line of lines) {
3676
+ const trimmed = line.trim();
3677
+ if (!trimmed || trimmed === "data: [DONE]") continue;
3678
+ if (!trimmed.startsWith("data:")) continue;
3679
+ try {
3680
+ const json = JSON.parse(trimmed.slice(5).trim());
3681
+ const text = resolvePath(json, extractPath);
3682
+ if (text && typeof text === "string") yield text;
3683
+ } catch (e) {
3684
+ }
3685
+ }
3686
+ }
3687
+ if (buffer.trim() && buffer.trim() !== "data: [DONE]") {
3688
+ const jsonStr = buffer.replace(/^data:\s*/, "").trim();
3689
+ try {
3690
+ const json = JSON.parse(jsonStr);
3691
+ const text = resolvePath(json, extractPath);
3692
+ if (text && typeof text === "string") yield text;
3693
+ } catch (e) {
3694
+ }
3351
3695
  }
3352
3696
  } finally {
3353
3697
  reader.releaseLock();
@@ -3355,8 +3699,8 @@ ${context != null ? context : "None"}` },
3355
3699
  });
3356
3700
  }
3357
3701
  async embed(text) {
3358
- var _a, _b;
3359
- const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
3702
+ var _a2, _b;
3703
+ const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
3360
3704
  let payload;
3361
3705
  if (this.opts.embedPayloadTemplate) {
3362
3706
  payload = buildPayload(this.opts.embedPayloadTemplate, {
@@ -3369,7 +3713,7 @@ ${context != null ? context : "None"}` },
3369
3713
  input: text
3370
3714
  };
3371
3715
  }
3372
- const { data } = await this.http.post(path, payload);
3716
+ const { data } = await this.http.post(path2, payload);
3373
3717
  const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
3374
3718
  const vector = resolvePath(data, extractPath);
3375
3719
  if (!Array.isArray(vector)) {
@@ -3437,13 +3781,13 @@ var AuthenticationException = class extends RetrivoraError {
3437
3781
  }
3438
3782
  };
3439
3783
  function wrapError(err, defaultCode, defaultMessage) {
3440
- var _a;
3784
+ var _a2;
3441
3785
  if (err instanceof RetrivoraError) {
3442
3786
  return err;
3443
3787
  }
3444
3788
  const error = err;
3445
3789
  const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
3446
- const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a = error == null ? void 0 : error.response) == null ? void 0 : _a.status);
3790
+ const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
3447
3791
  const code = error == null ? void 0 : error.code;
3448
3792
  if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
3449
3793
  return new RateLimitException(message, err);
@@ -3507,6 +3851,8 @@ var LLMFactory = class _LLMFactory {
3507
3851
  "anthropic",
3508
3852
  "ollama",
3509
3853
  "gemini",
3854
+ "groq",
3855
+ "qwen",
3510
3856
  "rest",
3511
3857
  "universal_rest",
3512
3858
  "custom",
@@ -3514,7 +3860,7 @@ var LLMFactory = class _LLMFactory {
3514
3860
  ];
3515
3861
  }
3516
3862
  static create(llmConfig, embeddingConfig) {
3517
- var _a, _b, _c;
3863
+ var _a2, _b, _c;
3518
3864
  switch (llmConfig.provider) {
3519
3865
  case "openai":
3520
3866
  return new OpenAIProvider(llmConfig, embeddingConfig);
@@ -3524,12 +3870,16 @@ var LLMFactory = class _LLMFactory {
3524
3870
  return new OllamaProvider(llmConfig, embeddingConfig);
3525
3871
  case "gemini":
3526
3872
  return new GeminiProvider(llmConfig, embeddingConfig);
3873
+ case "groq":
3874
+ return new GroqProvider(llmConfig, embeddingConfig);
3875
+ case "qwen":
3876
+ return new QwenProvider(llmConfig, embeddingConfig);
3527
3877
  case "rest":
3528
3878
  case "universal_rest":
3529
3879
  case "custom":
3530
3880
  return new UniversalLLMAdapter(llmConfig);
3531
3881
  default: {
3532
- const providerName = String((_a = llmConfig.provider) != null ? _a : "").toLowerCase();
3882
+ const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
3533
3883
  const customFactory = customProviders.get(providerName);
3534
3884
  if (customFactory) {
3535
3885
  return customFactory(llmConfig);
@@ -3566,6 +3916,10 @@ var LLMFactory = class _LLMFactory {
3566
3916
  return OllamaProvider;
3567
3917
  case "gemini":
3568
3918
  return GeminiProvider;
3919
+ case "groq":
3920
+ return GroqProvider;
3921
+ case "qwen":
3922
+ return QwenProvider;
3569
3923
  case "rest":
3570
3924
  case "universal_rest":
3571
3925
  case "custom":
@@ -3627,7 +3981,7 @@ var ProviderRegistry = class {
3627
3981
  return null;
3628
3982
  }
3629
3983
  static async loadVectorProviderClass(provider) {
3630
- var _a;
3984
+ var _a2;
3631
3985
  if (this.vectorProviders[provider]) return this.vectorProviders[provider];
3632
3986
  switch (provider) {
3633
3987
  case "pinecone": {
@@ -3636,7 +3990,7 @@ var ProviderRegistry = class {
3636
3990
  }
3637
3991
  case "pgvector":
3638
3992
  case "postgresql": {
3639
- const postgresMode = ((_a = process.env.POSTGRES_MODE) != null ? _a : "multi").toLowerCase();
3993
+ const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
3640
3994
  if (postgresMode === "single") {
3641
3995
  const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
3642
3996
  return PostgreSQLProvider2;
@@ -4085,11 +4439,11 @@ var LlamaIndexIngestor = class {
4085
4439
  * than standard character-count splitting.
4086
4440
  */
4087
4441
  async chunk(text, options = {}) {
4088
- var _a, _b;
4442
+ var _a2, _b;
4089
4443
  try {
4090
4444
  const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
4091
4445
  const splitter = new SentenceSplitter({
4092
- chunkSize: (_a = options.chunkSize) != null ? _a : 1e3,
4446
+ chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
4093
4447
  chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
4094
4448
  });
4095
4449
  const doc = new Document({ text, metadata: options.metadata || {} });
@@ -4198,7 +4552,7 @@ ${error instanceof Error ? error.message : String(error)}`
4198
4552
  * The agent returns `{ messages: [...] }` — the last message is the final answer.
4199
4553
  */
4200
4554
  async run(input, chatHistory = []) {
4201
- var _a, _b, _c;
4555
+ var _a2, _b, _c;
4202
4556
  if (!this.agent) {
4203
4557
  throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
4204
4558
  }
@@ -4209,7 +4563,7 @@ ${error instanceof Error ? error.message : String(error)}`
4209
4563
  const response = await this.agent.invoke({
4210
4564
  messages: [...historyMessages, new HumanMessage(input)]
4211
4565
  });
4212
- const lastMessage = (_a = response == null ? void 0 : response.messages) == null ? void 0 : _a.at(-1);
4566
+ const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
4213
4567
  if (lastMessage && typeof lastMessage.content === "string") {
4214
4568
  return lastMessage.content;
4215
4569
  }
@@ -4220,6 +4574,437 @@ ${error instanceof Error ? error.message : String(error)}`
4220
4574
  }
4221
4575
  };
4222
4576
 
4577
+ // src/core/mcp.ts
4578
+ var import_child_process = require("child_process");
4579
+ var MCPClient = class {
4580
+ constructor(config) {
4581
+ this.config = config;
4582
+ this.messageIdCounter = 0;
4583
+ this.pendingRequests = /* @__PURE__ */ new Map();
4584
+ this.stdioBuffer = "";
4585
+ this.initialized = false;
4586
+ }
4587
+ getNextMessageId() {
4588
+ return ++this.messageIdCounter;
4589
+ }
4590
+ /**
4591
+ * Connect and initialize the MCP server connection.
4592
+ */
4593
+ async connect() {
4594
+ if (this.initialized) return;
4595
+ if (this.config.transport === "stdio") {
4596
+ await this.connectStdio();
4597
+ } else {
4598
+ await this.connectSSE();
4599
+ }
4600
+ try {
4601
+ const response = await this.sendJsonRpc("initialize", {
4602
+ protocolVersion: "2024-11-05",
4603
+ capabilities: {},
4604
+ clientInfo: {
4605
+ name: "retrivora-sdk",
4606
+ version: "1.0.0"
4607
+ }
4608
+ });
4609
+ await this.sendNotification("notifications/initialized");
4610
+ this.initialized = true;
4611
+ console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
4612
+ } catch (err) {
4613
+ this.disconnect();
4614
+ throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
4615
+ }
4616
+ }
4617
+ async connectStdio() {
4618
+ var _a2;
4619
+ const cmd = this.config.command;
4620
+ if (!cmd) {
4621
+ throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
4622
+ }
4623
+ const args = this.config.args || [];
4624
+ const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
4625
+ this.childProcess = (0, import_child_process.spawn)(cmd, args, { env, shell: true });
4626
+ if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
4627
+ throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
4628
+ }
4629
+ this.childProcess.stdout.on("data", (data) => {
4630
+ this.stdioBuffer += data.toString("utf-8");
4631
+ this.processStdioLines();
4632
+ });
4633
+ (_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
4634
+ console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
4635
+ });
4636
+ this.childProcess.on("close", (code) => {
4637
+ console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
4638
+ this.disconnect();
4639
+ });
4640
+ await new Promise((resolve) => setTimeout(resolve, 100));
4641
+ }
4642
+ processStdioLines() {
4643
+ let newlineIndex;
4644
+ while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
4645
+ const line = this.stdioBuffer.substring(0, newlineIndex).trim();
4646
+ this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
4647
+ if (!line) continue;
4648
+ try {
4649
+ const payload = JSON.parse(line);
4650
+ if (payload.id !== void 0) {
4651
+ const req = this.pendingRequests.get(Number(payload.id));
4652
+ if (req) {
4653
+ this.pendingRequests.delete(Number(payload.id));
4654
+ if (payload.error) {
4655
+ req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
4656
+ } else {
4657
+ req.resolve(payload.result);
4658
+ }
4659
+ }
4660
+ }
4661
+ } catch (e) {
4662
+ console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
4663
+ }
4664
+ }
4665
+ }
4666
+ async connectSSE() {
4667
+ if (!this.config.url) {
4668
+ throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
4669
+ }
4670
+ this.sseUrl = this.config.url;
4671
+ }
4672
+ async sendJsonRpc(method, params) {
4673
+ const id = this.getNextMessageId();
4674
+ const request = {
4675
+ jsonrpc: "2.0",
4676
+ id,
4677
+ method,
4678
+ params
4679
+ };
4680
+ if (this.config.transport === "stdio") {
4681
+ if (!this.childProcess || !this.childProcess.stdin) {
4682
+ throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
4683
+ }
4684
+ return new Promise((resolve, reject) => {
4685
+ this.pendingRequests.set(id, { resolve, reject });
4686
+ this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
4687
+ });
4688
+ } else {
4689
+ if (!this.sseUrl) {
4690
+ throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
4691
+ }
4692
+ const response = await fetch(this.sseUrl, {
4693
+ method: "POST",
4694
+ headers: { "Content-Type": "application/json" },
4695
+ body: JSON.stringify(request)
4696
+ });
4697
+ if (!response.ok) {
4698
+ throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
4699
+ }
4700
+ const payload = await response.json();
4701
+ if (payload.error) {
4702
+ throw new Error(payload.error.message || JSON.stringify(payload.error));
4703
+ }
4704
+ return payload.result;
4705
+ }
4706
+ }
4707
+ async sendNotification(method, params) {
4708
+ var _a2;
4709
+ const notification = {
4710
+ jsonrpc: "2.0",
4711
+ method,
4712
+ params
4713
+ };
4714
+ if (this.config.transport === "stdio") {
4715
+ if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
4716
+ this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
4717
+ }
4718
+ } else if (this.sseUrl) {
4719
+ await fetch(this.sseUrl, {
4720
+ method: "POST",
4721
+ headers: { "Content-Type": "application/json" },
4722
+ body: JSON.stringify(notification)
4723
+ }).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
4724
+ }
4725
+ }
4726
+ /**
4727
+ * List all tools offered by the MCP server.
4728
+ */
4729
+ async listTools() {
4730
+ await this.connect();
4731
+ const result = await this.sendJsonRpc("tools/list", {});
4732
+ return (result == null ? void 0 : result.tools) || [];
4733
+ }
4734
+ /**
4735
+ * Execute a tool on the MCP server.
4736
+ */
4737
+ async callTool(name, args = {}) {
4738
+ await this.connect();
4739
+ return await this.sendJsonRpc("tools/call", { name, arguments: args });
4740
+ }
4741
+ disconnect() {
4742
+ this.initialized = false;
4743
+ this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
4744
+ this.pendingRequests.clear();
4745
+ if (this.childProcess) {
4746
+ try {
4747
+ this.childProcess.kill();
4748
+ } catch (e) {
4749
+ }
4750
+ this.childProcess = void 0;
4751
+ }
4752
+ }
4753
+ };
4754
+ var MCPRegistry = class {
4755
+ constructor(servers = []) {
4756
+ this.clients = [];
4757
+ this.clients = servers.map((cfg) => new MCPClient(cfg));
4758
+ }
4759
+ async getAllTools() {
4760
+ const list = [];
4761
+ await Promise.all(
4762
+ this.clients.map(async (client) => {
4763
+ try {
4764
+ const tools = await client.listTools();
4765
+ tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
4766
+ } catch (e) {
4767
+ console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
4768
+ }
4769
+ })
4770
+ );
4771
+ return list;
4772
+ }
4773
+ async callTool(toolName, args = {}) {
4774
+ for (const client of this.clients) {
4775
+ try {
4776
+ const tools = await client.listTools();
4777
+ if (tools.some((t) => t.name === toolName)) {
4778
+ return await client.callTool(toolName, args);
4779
+ }
4780
+ } catch (e) {
4781
+ }
4782
+ }
4783
+ throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
4784
+ }
4785
+ disconnectAll() {
4786
+ this.clients.forEach((c) => c.disconnect());
4787
+ }
4788
+ };
4789
+
4790
+ // src/core/MultiAgentCoordinator.ts
4791
+ var MultiAgentCoordinator = class {
4792
+ constructor(options) {
4793
+ var _a2;
4794
+ this.llmProvider = options.llmProvider;
4795
+ this.mcpRegistry = options.mcpRegistry;
4796
+ this.documentSearch = options.documentSearch;
4797
+ this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
4798
+ }
4799
+ /**
4800
+ * Run the multi-agent coordination loop synchronously and return the final response.
4801
+ */
4802
+ async run(question, history = []) {
4803
+ const generator = this.runStream(question, history);
4804
+ let finalReply = "";
4805
+ const sources = [];
4806
+ try {
4807
+ for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
4808
+ const chunk = temp.value;
4809
+ if (typeof chunk === "string") {
4810
+ finalReply += chunk;
4811
+ } else if (chunk && typeof chunk === "object") {
4812
+ if ("reply" in chunk && chunk.reply) {
4813
+ finalReply += chunk.reply;
4814
+ }
4815
+ if ("sources" in chunk && chunk.sources) {
4816
+ sources.push(...chunk.sources);
4817
+ }
4818
+ }
4819
+ }
4820
+ } catch (temp) {
4821
+ error = [temp];
4822
+ } finally {
4823
+ try {
4824
+ more && (temp = iter.return) && await temp.call(iter);
4825
+ } finally {
4826
+ if (error)
4827
+ throw error[0];
4828
+ }
4829
+ }
4830
+ return {
4831
+ reply: finalReply,
4832
+ sources
4833
+ };
4834
+ }
4835
+ /**
4836
+ * Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
4837
+ */
4838
+ runStream(_0) {
4839
+ return __asyncGenerator(this, arguments, function* (question, history = []) {
4840
+ const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
4841
+ let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
4842
+ You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
4843
+
4844
+ Available Tools:
4845
+ - document_search(query: string): Search the vector database and knowledge base for documents.
4846
+
4847
+ ${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
4848
+ ${mcpTools.map((mt) => {
4849
+ var _a2;
4850
+ return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
4851
+ }).join("\n")}
4852
+
4853
+ Tool Calling Protocol:
4854
+ If you need to call a tool, write:
4855
+ TOOL_CALL: <toolName>({ "argName": "value" })
4856
+ And then STOP generating immediately.
4857
+
4858
+ Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
4859
+ `;
4860
+ const supervisorHistory = [
4861
+ { role: "system", content: systemPrompt },
4862
+ ...history,
4863
+ { role: "user", content: question }
4864
+ ];
4865
+ let iteration = 0;
4866
+ const allSources = [];
4867
+ while (iteration < this.maxIterations) {
4868
+ iteration++;
4869
+ const context = "";
4870
+ let fullModelResponse = "";
4871
+ let textBuffer = "";
4872
+ let inThinking = false;
4873
+ let toolCallDetected = null;
4874
+ if (!this.llmProvider.chatStream) {
4875
+ const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
4876
+ fullModelResponse = reply;
4877
+ const thinkIndex = reply.indexOf("<think>");
4878
+ const endThinkIndex = reply.indexOf("</think>");
4879
+ let thinkingText = "";
4880
+ let answerText = reply;
4881
+ if (thinkIndex !== -1 && endThinkIndex !== -1) {
4882
+ thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
4883
+ answerText = reply.substring(endThinkIndex + 8);
4884
+ yield { type: "thinking", text: thinkingText };
4885
+ }
4886
+ const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
4887
+ if (toolMatch) {
4888
+ const toolName = toolMatch[1];
4889
+ const toolArgsStr = toolMatch[2];
4890
+ try {
4891
+ const toolArgs = JSON.parse(toolArgsStr.trim());
4892
+ toolCallDetected = { name: toolName, args: toolArgs };
4893
+ } catch (e) {
4894
+ console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
4895
+ }
4896
+ } else {
4897
+ yield answerText;
4898
+ }
4899
+ } else {
4900
+ const stream = this.llmProvider.chatStream(supervisorHistory, context);
4901
+ try {
4902
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
4903
+ const chunk = temp.value;
4904
+ fullModelResponse += chunk;
4905
+ textBuffer += chunk;
4906
+ if (!inThinking && textBuffer.includes("<think>")) {
4907
+ inThinking = true;
4908
+ const idx = textBuffer.indexOf("<think>");
4909
+ textBuffer = textBuffer.slice(idx + 7);
4910
+ }
4911
+ if (inThinking && textBuffer.includes("</think>")) {
4912
+ inThinking = false;
4913
+ const idx = textBuffer.indexOf("</think>");
4914
+ const thinkingDelta = textBuffer.slice(0, idx);
4915
+ yield { type: "thinking", text: thinkingDelta };
4916
+ textBuffer = textBuffer.slice(idx + 8);
4917
+ }
4918
+ if (inThinking && textBuffer.length > 0) {
4919
+ yield { type: "thinking", text: textBuffer };
4920
+ textBuffer = "";
4921
+ }
4922
+ if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
4923
+ const idx = textBuffer.indexOf("TOOL_CALL:");
4924
+ const precedingText = textBuffer.slice(0, idx);
4925
+ if (precedingText.trim()) {
4926
+ yield precedingText;
4927
+ }
4928
+ textBuffer = textBuffer.slice(idx);
4929
+ }
4930
+ if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
4931
+ yield textBuffer;
4932
+ textBuffer = "";
4933
+ }
4934
+ }
4935
+ } catch (temp) {
4936
+ error = [temp];
4937
+ } finally {
4938
+ try {
4939
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
4940
+ } finally {
4941
+ if (error)
4942
+ throw error[0];
4943
+ }
4944
+ }
4945
+ if (textBuffer.trim()) {
4946
+ const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
4947
+ if (toolMatch) {
4948
+ const toolName = toolMatch[1];
4949
+ const toolArgsStr = toolMatch[2];
4950
+ try {
4951
+ const toolArgs = JSON.parse(toolArgsStr.trim());
4952
+ toolCallDetected = { name: toolName, args: toolArgs };
4953
+ } catch (e) {
4954
+ console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
4955
+ }
4956
+ } else {
4957
+ yield textBuffer;
4958
+ }
4959
+ }
4960
+ }
4961
+ supervisorHistory.push({ role: "assistant", content: fullModelResponse });
4962
+ if (toolCallDetected) {
4963
+ const { name: toolName, args: toolArgs } = toolCallDetected;
4964
+ yield {
4965
+ type: "thinking",
4966
+ text: `
4967
+ [Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
4968
+ `
4969
+ };
4970
+ let toolResultText = "";
4971
+ try {
4972
+ if (toolName === "document_search") {
4973
+ const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
4974
+ toolResultText = `document_search returned:
4975
+ ${searchRes.reply}
4976
+
4977
+ Sources count: ${searchRes.sources.length}`;
4978
+ if (searchRes.sources && searchRes.sources.length > 0) {
4979
+ allSources.push(...searchRes.sources);
4980
+ yield { reply: "", sources: searchRes.sources };
4981
+ }
4982
+ } else {
4983
+ const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
4984
+ toolResultText = `MCP Tool "${toolName}" returned:
4985
+ ${JSON.stringify(mcpRes.content)}`;
4986
+ }
4987
+ } catch (err) {
4988
+ toolResultText = `Error calling tool "${toolName}": ${err.message}`;
4989
+ }
4990
+ supervisorHistory.push({
4991
+ role: "user",
4992
+ content: `TOOL_RESULT for ${toolName}:
4993
+ ${toolResultText}`
4994
+ });
4995
+ yield {
4996
+ type: "thinking",
4997
+ text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
4998
+ `
4999
+ };
5000
+ } else {
5001
+ break;
5002
+ }
5003
+ }
5004
+ });
5005
+ }
5006
+ };
5007
+
4223
5008
  // src/core/BatchProcessor.ts
4224
5009
  function isTransientError(error) {
4225
5010
  if (!(error instanceof Error)) return false;
@@ -4540,7 +5325,7 @@ var QueryProcessor = class {
4540
5325
  * @param validFields Optional list of known filterable fields to look for
4541
5326
  */
4542
5327
  static extractQueryFieldHints(question, validFields = []) {
4543
- var _a, _b, _c, _d;
5328
+ var _a2, _b, _c, _d;
4544
5329
  if (!question.trim()) return [];
4545
5330
  const hints = /* @__PURE__ */ new Map();
4546
5331
  const addHint = (value, field) => {
@@ -4620,7 +5405,7 @@ var QueryProcessor = class {
4620
5405
  ];
4621
5406
  for (const p of universalPatterns) {
4622
5407
  for (const match of question.matchAll(p.regex)) {
4623
- const val = p.group ? (_a = match[p.group]) != null ? _a : match[0] : match[0];
5408
+ const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
4624
5409
  if (!val) continue;
4625
5410
  if (p.field) addHint(val, p.field);
4626
5411
  else addHint(val);
@@ -4844,11 +5629,11 @@ var LLMRouter = class {
4844
5629
  * When provided it is used directly as the 'default' role without re-constructing.
4845
5630
  */
4846
5631
  async initialize(prebuiltDefault) {
4847
- var _a;
5632
+ var _a2;
4848
5633
  const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
4849
5634
  this.models.set("default", defaultModel);
4850
5635
  const envFastModel = process.env.FAST_LLM_MODEL;
4851
- const providerFastDefault = (_a = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a : "";
5636
+ const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
4852
5637
  const fastModelName = envFastModel || providerFastDefault;
4853
5638
  if (fastModelName && fastModelName !== this.config.llm.model) {
4854
5639
  console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
@@ -4867,8 +5652,8 @@ var LLMRouter = class {
4867
5652
  * Falls back to 'default' if the requested role is not registered.
4868
5653
  */
4869
5654
  get(role) {
4870
- var _a;
4871
- const provider = (_a = this.models.get(role)) != null ? _a : this.models.get("default");
5655
+ var _a2;
5656
+ const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
4872
5657
  if (!provider) {
4873
5658
  throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
4874
5659
  }
@@ -4886,7 +5671,7 @@ var UITransformer = class _UITransformer {
4886
5671
  * Prefer `analyzeAndDecide()` in production.
4887
5672
  */
4888
5673
  static transform(userQuery, retrievedData, config, trainedSchema, intent) {
4889
- var _a, _b, _c;
5674
+ var _a2, _b, _c;
4890
5675
  if (!retrievedData || retrievedData.length === 0) {
4891
5676
  return this.createTextResponse("No data available", "No relevant data found for your query.");
4892
5677
  }
@@ -4906,7 +5691,7 @@ var UITransformer = class _UITransformer {
4906
5691
  return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
4907
5692
  }
4908
5693
  if (resolvedIntent.visualizationHint === "distribution") {
4909
- return (_a = this.transformToHistogram(profile, userQuery)) != null ? _a : this.transformToBarChart(filteredData, profile, userQuery);
5694
+ return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
4910
5695
  }
4911
5696
  if (resolvedIntent.visualizationHint === "correlation") {
4912
5697
  return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
@@ -5231,11 +6016,11 @@ ${schemaProfileText}` : ""}`;
5231
6016
  };
5232
6017
  }
5233
6018
  static transformToPieChart(data, profile, query = "") {
5234
- var _a;
6019
+ var _a2;
5235
6020
  const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
5236
6021
  const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
5237
- var _a2;
5238
- return String((_a2 = record.fields[dimension.key]) != null ? _a2 : "");
6022
+ var _a3;
6023
+ return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
5239
6024
  }).filter(Boolean))) : this.detectCategories(data);
5240
6025
  if (categories.length === 0) return null;
5241
6026
  const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
@@ -5245,7 +6030,7 @@ ${schemaProfileText}` : ""}`;
5245
6030
  });
5246
6031
  return {
5247
6032
  type: "pie_chart",
5248
- title: `Distribution by ${(_a = dimension == null ? void 0 : dimension.label) != null ? _a : "Category"}`,
6033
+ title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
5249
6034
  description: `Showing breakdown across ${pieData.length} categories`,
5250
6035
  data: pieData
5251
6036
  };
@@ -5255,8 +6040,8 @@ ${schemaProfileText}` : ""}`;
5255
6040
  const valueField = profile.numericFields[0];
5256
6041
  const buckets = /* @__PURE__ */ new Map();
5257
6042
  profile.records.forEach((record) => {
5258
- var _a, _b, _c;
5259
- const timestamp = String((_a = record.fields[dateField.key]) != null ? _a : "");
6043
+ var _a2, _b, _c;
6044
+ const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
5260
6045
  const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
5261
6046
  buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
5262
6047
  });
@@ -5269,23 +6054,23 @@ ${schemaProfileText}` : ""}`;
5269
6054
  };
5270
6055
  }
5271
6056
  static transformToBarChart(data, profile, query = "", horizontal = false) {
5272
- var _a;
6057
+ var _a2;
5273
6058
  const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
5274
6059
  const measure = profile ? this.selectNumericField(profile, query) : void 0;
5275
6060
  const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
5276
6061
  const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
5277
6062
  const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
5278
- var _a2, _b, _c, _d, _e;
6063
+ var _a3, _b, _c, _d, _e;
5279
6064
  const meta = item.metadata || {};
5280
6065
  const label = String(
5281
- (_c = (_b = (_a2 = this.getDynamicVal(meta, "name")) != null ? _a2 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
6066
+ (_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
5282
6067
  );
5283
6068
  const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
5284
6069
  return { category: label, value: Number(value) };
5285
6070
  });
5286
6071
  return {
5287
6072
  type: horizontal ? "horizontal_bar" : "bar_chart",
5288
- title: dimension ? `${(_a = measure == null ? void 0 : measure.label) != null ? _a : "Count"} by ${dimension.label}` : "Comparison",
6073
+ title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
5289
6074
  description: `Showing ${fallbackData.length} comparable values`,
5290
6075
  data: fallbackData
5291
6076
  };
@@ -5320,11 +6105,11 @@ ${schemaProfileText}` : ""}`;
5320
6105
  if (fields.length < 2) return null;
5321
6106
  const [xField, yField] = fields;
5322
6107
  const points = profile.records.map((record) => {
5323
- var _a;
6108
+ var _a2;
5324
6109
  const x = this.toFiniteNumber(record.fields[xField.key]);
5325
6110
  const y = this.toFiniteNumber(record.fields[yField.key]);
5326
6111
  if (x === null || y === null) return null;
5327
- return { x, y, label: String((_a = this.getRecordLabel(record)) != null ? _a : record.id) };
6112
+ return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
5328
6113
  }).filter((point) => point !== null).slice(0, 100);
5329
6114
  if (points.length === 0) return null;
5330
6115
  return {
@@ -5354,9 +6139,9 @@ ${schemaProfileText}` : ""}`;
5354
6139
  static transformToRadarChart(data) {
5355
6140
  const attributeMap = {};
5356
6141
  data.forEach((item) => {
5357
- var _a, _b, _c;
6142
+ var _a2, _b, _c;
5358
6143
  const meta = item.metadata || {};
5359
- const seriesName = String((_c = (_b = (_a = meta.name) != null ? _a : meta.product) != null ? _b : item.id) != null ? _c : "Item");
6144
+ const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
5360
6145
  Object.entries(meta).forEach(([key, val]) => {
5361
6146
  if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
5362
6147
  if (!attributeMap[key]) attributeMap[key] = {};
@@ -5438,22 +6223,22 @@ ${schemaProfileText}` : ""}`;
5438
6223
  return null;
5439
6224
  }
5440
6225
  static normalizeTransformation(payload) {
5441
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6226
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
5442
6227
  if (!payload || typeof payload !== "object") return null;
5443
6228
  const p = payload;
5444
6229
  const type = this.normalizeVisualizationType(
5445
- String((_c = (_b = (_a = p.type) != null ? _a : p.view) != null ? _b : p.chartType) != null ? _c : "")
6230
+ String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
5446
6231
  );
5447
6232
  if (!type) return null;
5448
6233
  const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
5449
6234
  const description = p.description ? String(p.description) : void 0;
5450
- const rawData = (_j = (_i = (_h = (_g = (_f = p.data) != null ? _f : p.table) != null ? _g : p.rows) != null ? _h : p.items) != null ? _i : p.content) != null ? _j : null;
6235
+ const rawData = (_j = (_i = (_h = (_g2 = (_f = p.data) != null ? _f : p.table) != null ? _g2 : p.rows) != null ? _h : p.items) != null ? _i : p.content) != null ? _j : null;
5451
6236
  const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
5452
6237
  const transformation = { type, title, description, data };
5453
6238
  return this.validateTransformation(transformation) ? transformation : null;
5454
6239
  }
5455
6240
  static normalizeVisualizationType(type) {
5456
- var _a;
6241
+ var _a2;
5457
6242
  const mapping = {
5458
6243
  pie: "pie_chart",
5459
6244
  pie_chart: "pie_chart",
@@ -5481,7 +6266,7 @@ ${schemaProfileText}` : ""}`;
5481
6266
  product_carousel: "product_carousel",
5482
6267
  carousel: "carousel"
5483
6268
  };
5484
- return (_a = mapping[type.toLowerCase()]) != null ? _a : null;
6269
+ return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
5485
6270
  }
5486
6271
  static validateTransformation(t) {
5487
6272
  const { type, data } = t;
@@ -5683,16 +6468,16 @@ ${schemaProfileText}` : ""}`;
5683
6468
  return null;
5684
6469
  }
5685
6470
  static selectDimensionField(profile, query) {
5686
- var _a, _b;
6471
+ var _a2, _b;
5687
6472
  const productCategory = profile.categoricalFields.find(
5688
6473
  (field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
5689
6474
  );
5690
6475
  const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
5691
- return (_b = (_a = ranked[0]) != null ? _a : productCategory) != null ? _b : profile.categoricalFields[0];
6476
+ return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
5692
6477
  }
5693
6478
  static selectNumericField(profile, query) {
5694
- var _a;
5695
- return (_a = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a : profile.numericFields[0];
6479
+ var _a2;
6480
+ return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
5696
6481
  }
5697
6482
  static rankFieldsByQuery(fields, query) {
5698
6483
  const q = query.toLowerCase();
@@ -5721,8 +6506,8 @@ ${schemaProfileText}` : ""}`;
5721
6506
  static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
5722
6507
  const result = {};
5723
6508
  profile.records.forEach((record) => {
5724
- var _a, _b, _c;
5725
- const category = String((_a = record.fields[dimensionKey]) != null ? _a : "Other").trim() || "Other";
6509
+ var _a2, _b, _c;
6510
+ const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
5726
6511
  const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
5727
6512
  result[category] = ((_c = result[category]) != null ? _c : 0) + value;
5728
6513
  });
@@ -5801,8 +6586,8 @@ ${schemaProfileText}` : ""}`;
5801
6586
  static aggregateByCategory(data, categories) {
5802
6587
  const result = Object.fromEntries(categories.map((c) => [c, 0]));
5803
6588
  data.forEach((item) => {
5804
- var _a;
5805
- const cat = (_a = this.getProductCategory(item)) != null ? _a : "Other";
6589
+ var _a2;
6590
+ const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
5806
6591
  if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
5807
6592
  else result["Other"] = (result["Other"] || 0) + 1;
5808
6593
  });
@@ -5810,17 +6595,17 @@ ${schemaProfileText}` : ""}`;
5810
6595
  }
5811
6596
  static extractTimeSeriesData(data) {
5812
6597
  return data.map((item) => {
5813
- var _a, _b, _c, _d, _e;
6598
+ var _a2, _b, _c, _d, _e;
5814
6599
  const meta = item.metadata || {};
5815
6600
  return {
5816
- timestamp: (_b = (_a = meta.timestamp) != null ? _a : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
6601
+ timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
5817
6602
  value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
5818
6603
  label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
5819
6604
  };
5820
6605
  });
5821
6606
  }
5822
6607
  static extractNumericValue(meta) {
5823
- var _a;
6608
+ var _a2;
5824
6609
  const preferredKeys = [
5825
6610
  "value",
5826
6611
  "count",
@@ -5835,7 +6620,7 @@ ${schemaProfileText}` : ""}`;
5835
6620
  "price"
5836
6621
  ];
5837
6622
  for (const key of preferredKeys) {
5838
- const raw = (_a = resolveMetadataValue(meta, key)) != null ? _a : meta[key];
6623
+ const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
5839
6624
  const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
5840
6625
  if (Number.isFinite(value)) return value;
5841
6626
  }
@@ -5981,8 +6766,8 @@ ${schemaProfileText}` : ""}`;
5981
6766
  let inStock = 0;
5982
6767
  let outOfStock = 0;
5983
6768
  data.forEach((d) => {
5984
- var _a, _b;
5985
- const cat = (_a = this.getProductCategory(d)) != null ? _a : "Other";
6769
+ var _a2, _b;
6770
+ const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
5986
6771
  if (cat === category) {
5987
6772
  const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
5988
6773
  if (this.determineStockStatus(d)) inStock += quantity;
@@ -6026,9 +6811,9 @@ ${schemaProfileText}` : ""}`;
6026
6811
  }
6027
6812
  // ─── Product Extraction ───────────────────────────────────────────────────
6028
6813
  static getDynamicVal(meta, uiKey, config, trainedSchema) {
6029
- var _a;
6814
+ var _a2;
6030
6815
  if (!meta) return void 0;
6031
- const mapping = (_a = config == null ? void 0 : config.rag) == null ? void 0 : _a.uiMapping;
6816
+ const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
6032
6817
  if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
6033
6818
  if (trainedSchema && typeof trainedSchema === "object") {
6034
6819
  const trainedKey = trainedSchema[uiKey];
@@ -6037,13 +6822,13 @@ ${schemaProfileText}` : ""}`;
6037
6822
  return resolveMetadataValue(meta, uiKey);
6038
6823
  }
6039
6824
  static extractProductInfo(item, config, trainedSchema) {
6040
- var _a;
6825
+ var _a2;
6041
6826
  const meta = item.metadata || {};
6042
6827
  const name = this.getDynamicVal(meta, "name", config, trainedSchema);
6043
6828
  const price = this.getDynamicVal(meta, "price", config, trainedSchema);
6044
6829
  const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
6045
6830
  const description = this.cleanProductDescription(
6046
- (_a = this.extractProductDescriptionFromContent(item.content)) != null ? _a : this.getProductDescriptionValue(meta, config, trainedSchema)
6831
+ (_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
6047
6832
  );
6048
6833
  if (name || this.isProductData(item)) {
6049
6834
  let finalName = name ? String(name) : void 0;
@@ -6151,10 +6936,10 @@ RULES:
6151
6936
  }
6152
6937
  static buildContextSummary(sources, maxChars = 6e3) {
6153
6938
  const items = sources.map((s, i) => {
6154
- var _a, _b, _c, _d;
6939
+ var _a2, _b, _c, _d;
6155
6940
  return {
6156
6941
  index: i + 1,
6157
- content: (_b = (_a = s.content) == null ? void 0 : _a.substring(0, 400)) != null ? _b : "",
6942
+ content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
6158
6943
  metadata: (_c = s.metadata) != null ? _c : {},
6159
6944
  score: (_d = s.score) != null ? _d : 0
6160
6945
  };
@@ -6347,9 +7132,11 @@ var Pipeline = class {
6347
7132
  /** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
6348
7133
  this.embeddingCache = new LRUEmbeddingCache(500);
6349
7134
  this.initialised = false;
6350
- var _a, _b, _c, _d, _e;
7135
+ /** Namespace-specific static cold context cache for CAG */
7136
+ this.coldContexts = /* @__PURE__ */ new Map();
7137
+ var _a2, _b, _c, _d, _e;
6351
7138
  this.chunker = new DocumentChunker(
6352
- (_b = (_a = config.rag) == null ? void 0 : _a.chunkSize) != null ? _b : 1e3,
7139
+ (_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
6353
7140
  (_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
6354
7141
  );
6355
7142
  if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
@@ -6365,7 +7152,7 @@ var Pipeline = class {
6365
7152
  return this.initialised ? this.llmProvider : void 0;
6366
7153
  }
6367
7154
  async initialize() {
6368
- var _a;
7155
+ var _a2, _b, _c;
6369
7156
  if (this.initialised) return;
6370
7157
  const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
6371
7158
 
@@ -6408,12 +7195,47 @@ var Pipeline = class {
6408
7195
  this.entityExtractor = new EntityExtractor(this.llmProvider);
6409
7196
  }
6410
7197
  await this.vectorDB.initialize();
6411
- if (((_a = this.config.rag) == null ? void 0 : _a.architecture) === "agentic") {
7198
+ if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
7199
+ this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
7200
+ this.multiAgentCoordinator = new MultiAgentCoordinator({
7201
+ llmProvider: this.llmProvider,
7202
+ mcpRegistry: this.mcpRegistry,
7203
+ documentSearch: async (query) => {
7204
+ return this.runNormalQuery(query);
7205
+ }
7206
+ });
6412
7207
  this.agent = new LangChainAgent(this, this.config);
6413
7208
  await this.agent.initialize(this.llmProvider);
6414
7209
  }
7210
+ if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
7211
+ await this.loadColdContext(this.config.projectId);
7212
+ }
6415
7213
  this.initialised = true;
6416
7214
  }
7215
+ async loadColdContext(ns) {
7216
+ var _a2, _b;
7217
+ const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
7218
+ if (!cagConfig || !cagConfig.enabled) return;
7219
+ try {
7220
+ const coldNs = cagConfig.coldNamespace || ns;
7221
+ const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
7222
+ const queryText = cagConfig.coldQuery || "documentation";
7223
+ const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
7224
+ const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
7225
+ if (coldMatches.length > 0) {
7226
+ const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
7227
+ ${m.content}`).join("\n\n---\n\n");
7228
+ this.coldContexts.set(ns, formatted);
7229
+ console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
7230
+ } else {
7231
+ this.coldContexts.set(ns, "No cold context found.");
7232
+ console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
7233
+ }
7234
+ } catch (err) {
7235
+ console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
7236
+ this.coldContexts.set(ns, "Failed to load cold context.");
7237
+ }
7238
+ }
6417
7239
  /**
6418
7240
  * Ingest documents with automatic chunking, embedding, and batch upsert.
6419
7241
  */
@@ -6445,12 +7267,12 @@ var Pipeline = class {
6445
7267
  }
6446
7268
  /** Step 1: Chunk the document content. */
6447
7269
  async prepareChunks(doc) {
6448
- var _a, _b;
7270
+ var _a2, _b;
6449
7271
  if (this.llamaIngestor) {
6450
7272
  return this.llamaIngestor.chunk(doc.content, {
6451
7273
  docId: doc.docId,
6452
7274
  metadata: doc.metadata,
6453
- chunkSize: (_a = this.config.rag) == null ? void 0 : _a.chunkSize,
7275
+ chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
6454
7276
  chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
6455
7277
  });
6456
7278
  }
@@ -6521,12 +7343,37 @@ var Pipeline = class {
6521
7343
  extractionOptions
6522
7344
  );
6523
7345
  }
7346
+ async runNormalQuery(question, history = [], namespace) {
7347
+ const stream = this.askStreamInternal(question, history, namespace);
7348
+ let reply = "";
7349
+ let sources = [];
7350
+ try {
7351
+ for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
7352
+ const chunk = temp.value;
7353
+ if (typeof chunk === "string") {
7354
+ reply += chunk;
7355
+ } else if (typeof chunk === "object" && chunk !== null) {
7356
+ if ("reply" in chunk && chunk.reply) reply += chunk.reply;
7357
+ if ("sources" in chunk && chunk.sources) sources = chunk.sources;
7358
+ }
7359
+ }
7360
+ } catch (temp) {
7361
+ error = [temp];
7362
+ } finally {
7363
+ try {
7364
+ more && (temp = iter.return) && await temp.call(iter);
7365
+ } finally {
7366
+ if (error)
7367
+ throw error[0];
7368
+ }
7369
+ }
7370
+ return { reply, sources };
7371
+ }
6524
7372
  async ask(question, history = [], namespace) {
6525
- var _a;
7373
+ var _a2;
6526
7374
  await this.initialize();
6527
- if (((_a = this.config.rag) == null ? void 0 : _a.architecture) === "agentic" && this.agent) {
6528
- const agentReply = await this.agent.run(question, history);
6529
- return { reply: agentReply, sources: [] };
7375
+ if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7376
+ return await this.multiAgentCoordinator.run(question, history);
6530
7377
  }
6531
7378
  const stream = this.askStream(question, history, namespace);
6532
7379
  let reply = "";
@@ -6558,6 +7405,47 @@ var Pipeline = class {
6558
7405
  }
6559
7406
  return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
6560
7407
  }
7408
+ askStream(_0) {
7409
+ return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
7410
+ var _a2;
7411
+ yield new __await(this.initialize());
7412
+ if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
7413
+ const stream2 = this.multiAgentCoordinator.runStream(question, history);
7414
+ try {
7415
+ for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
7416
+ const chunk = temp.value;
7417
+ yield chunk;
7418
+ }
7419
+ } catch (temp) {
7420
+ error = [temp];
7421
+ } finally {
7422
+ try {
7423
+ more && (temp = iter.return) && (yield new __await(temp.call(iter)));
7424
+ } finally {
7425
+ if (error)
7426
+ throw error[0];
7427
+ }
7428
+ }
7429
+ return;
7430
+ }
7431
+ const stream = this.askStreamInternal(question, history, namespace);
7432
+ try {
7433
+ for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
7434
+ const chunk = temp2.value;
7435
+ yield chunk;
7436
+ }
7437
+ } catch (temp2) {
7438
+ error2 = [temp2];
7439
+ } finally {
7440
+ try {
7441
+ more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
7442
+ } finally {
7443
+ if (error2)
7444
+ throw error2[0];
7445
+ }
7446
+ }
7447
+ });
7448
+ }
6561
7449
  /**
6562
7450
  * High-performance streaming RAG flow.
6563
7451
  * Yields text chunks first, then the retrieval metadata + observability trace at the end.
@@ -6568,12 +7456,12 @@ var Pipeline = class {
6568
7456
  * - UITransformation is computed after text streaming and emitted with metadata
6569
7457
  * - SchemaMapper.train runs while answer generation streams
6570
7458
  */
6571
- askStream(_0) {
7459
+ askStreamInternal(_0) {
6572
7460
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
6573
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
7461
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
6574
7462
  yield new __await(this.initialize());
6575
7463
  const ns = namespace != null ? namespace : this.config.projectId;
6576
- const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
7464
+ const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
6577
7465
  const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
6578
7466
  const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
6579
7467
  const requestStart = performance.now();
@@ -6586,7 +7474,7 @@ var Pipeline = class {
6586
7474
  }
6587
7475
  const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
6588
7476
  const filter = QueryProcessor.buildQueryFilter(question, hints);
6589
- const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g = this.config.rag) == null ? void 0 : _g.filterableFields);
7477
+ const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
6590
7478
  if (numericPredicates.length > 0) {
6591
7479
  filter.__numericPredicates = numericPredicates;
6592
7480
  }
@@ -6652,6 +7540,32 @@ ${graphContext}
6652
7540
  VECTOR CONTEXT:
6653
7541
  ${context}`;
6654
7542
  }
7543
+ if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
7544
+ if (!this.coldContexts.has(ns)) {
7545
+ yield new __await(this.loadColdContext(ns));
7546
+ }
7547
+ const coldContext = this.coldContexts.get(ns);
7548
+ if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
7549
+ context = `COLD CONTEXT (STATIC KNOWLEDGE):
7550
+ ${coldContext}
7551
+
7552
+ RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
7553
+ ${context}`;
7554
+ }
7555
+ }
7556
+ yield {
7557
+ reply: "",
7558
+ sources: sources.map((s) => {
7559
+ var _a3;
7560
+ return {
7561
+ id: s.id,
7562
+ score: s.score,
7563
+ content: s.content,
7564
+ metadata: (_a3 = s.metadata) != null ? _a3 : {},
7565
+ namespace: ns
7566
+ };
7567
+ })
7568
+ };
6655
7569
  const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
6656
7570
  const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
6657
7571
  if (allMetadataKeys.length > 0 && !cachedSchema) {
@@ -6679,10 +7593,10 @@ ${context}`;
6679
7593
  let hallucinationScoringPromise = Promise.resolve(void 0);
6680
7594
  const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
6681
7595
  const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
6682
- const isNativeThinking = isClaude37 && (((_m = this.config.llm.options) == null ? void 0 : _m.thinking) === true || ((_n = this.config.llm.options) == null ? void 0 : _n.thinking) === "enabled" || ((_o = this.config.llm.options) == null ? void 0 : _o.thinking) !== false);
7596
+ const isNativeThinking = isClaude37 && (((_o = this.config.llm.options) == null ? void 0 : _o.thinking) === true || ((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === "enabled" || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) !== false);
6683
7597
  const modelNameLower = this.config.llm.model.toLowerCase();
6684
7598
  const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
6685
- const isSimulatedThinking = !isNativeThinking && (((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === true || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) === "enabled" || isReasoningModel && ((_r = this.config.llm.options) == null ? void 0 : _r.thinking) !== false);
7599
+ const isSimulatedThinking = !isNativeThinking && (((_r = this.config.llm.options) == null ? void 0 : _r.thinking) === true || ((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === "enabled" || isReasoningModel && ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) !== false);
6686
7600
  let finalRestrictionSuffix = restrictionSuffix;
6687
7601
  if (isSimulatedThinking) {
6688
7602
  finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
@@ -6690,7 +7604,7 @@ ${context}`;
6690
7604
  const hardenedHistory = [...history];
6691
7605
  const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
6692
7606
  const messages = [...hardenedHistory, userQuestion];
6693
- const systemPrompt = (_s = this.config.llm.systemPrompt) != null ? _s : "";
7607
+ const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
6694
7608
  const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
6695
7609
  let fullReply = "";
6696
7610
  let thinkingText = "";
@@ -6801,7 +7715,7 @@ ${context}`;
6801
7715
  }
6802
7716
  yield fullReply;
6803
7717
  }
6804
- const runHallucination = ((_t = this.config.llm.options) == null ? void 0 : _t.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_u = this.config.llm.options) == null ? void 0 : _u.hallucinationScoring) !== false;
7718
+ const runHallucination = ((_v = this.config.llm.options) == null ? void 0 : _v.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) !== false;
6805
7719
  if (runHallucination) {
6806
7720
  hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
6807
7721
  }
@@ -6810,7 +7724,7 @@ ${context}`;
6810
7724
  const latency = {
6811
7725
  embedMs: Math.round(embedMs),
6812
7726
  retrieveMs: Math.round(retrieveMs),
6813
- rerankMs: ((_v = this.config.rag) == null ? void 0 : _v.useReranking) ? Math.round(rerankMs) : void 0,
7727
+ rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
6814
7728
  generateMs: Math.round(generateMs),
6815
7729
  totalMs: Math.round(totalMs)
6816
7730
  };
@@ -6823,33 +7737,63 @@ ${context}`;
6823
7737
  totalTokens: promptTokens + completionTokens,
6824
7738
  estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
6825
7739
  };
7740
+ const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
6826
7741
  const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
6827
7742
  uiTransformationPromise,
6828
- hallucinationScoringPromise
7743
+ awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
6829
7744
  ]));
6830
- const trace = __spreadValues({
7745
+ const buildTrace = (hScore) => __spreadValues({
6831
7746
  requestId,
6832
7747
  query: question,
6833
7748
  rewrittenQuery,
6834
7749
  systemPrompt,
6835
7750
  userPrompt: question + finalRestrictionSuffix,
6836
7751
  chunks: sources.map((s) => {
6837
- var _a2;
7752
+ var _a3;
6838
7753
  return {
6839
7754
  id: s.id,
6840
7755
  score: s.score,
6841
7756
  content: s.content,
6842
- metadata: (_a2 = s.metadata) != null ? _a2 : {},
7757
+ metadata: (_a3 = s.metadata) != null ? _a3 : {},
6843
7758
  namespace: ns
6844
7759
  };
6845
7760
  }),
6846
7761
  latency,
6847
7762
  tokens,
6848
7763
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
6849
- }, hallucinationResult ? {
6850
- hallucinationScore: hallucinationResult.score,
6851
- hallucinationReason: hallucinationResult.reason
7764
+ }, hScore ? {
7765
+ hallucinationScore: hScore.score,
7766
+ hallucinationReason: hScore.reason
6852
7767
  } : {});
7768
+ const trace = buildTrace(hallucinationResult);
7769
+ if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
7770
+ const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
7771
+ const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
7772
+ (async () => {
7773
+ try {
7774
+ let finalTrace = trace;
7775
+ if (!awaitHallucination && runHallucination) {
7776
+ const backgroundScoreResult = await hallucinationScoringPromise;
7777
+ if (backgroundScoreResult) {
7778
+ finalTrace = buildTrace(backgroundScoreResult);
7779
+ }
7780
+ }
7781
+ await fetch(absoluteUrl, {
7782
+ method: "POST",
7783
+ headers: {
7784
+ "Content-Type": "application/json"
7785
+ },
7786
+ body: JSON.stringify({
7787
+ trace: finalTrace,
7788
+ licenseKey: this.config.licenseKey,
7789
+ projectId: ns
7790
+ })
7791
+ });
7792
+ } catch (err) {
7793
+ console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
7794
+ }
7795
+ })();
7796
+ }
6853
7797
  yield {
6854
7798
  reply: "",
6855
7799
  sources,
@@ -6869,7 +7813,7 @@ ${context}`;
6869
7813
  * Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
6870
7814
  */
6871
7815
  async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
6872
- var _a;
7816
+ var _a2;
6873
7817
  if (!sources || sources.length === 0) {
6874
7818
  return UITransformer.transform(question, sources, this.config, cachedSchema);
6875
7819
  }
@@ -6883,7 +7827,7 @@ ${context}`;
6883
7827
  );
6884
7828
  }
6885
7829
  const isLocalProvider = this.config.llm.provider === "ollama";
6886
- const disableLlmUiTransform = ((_a = this.config.llm.options) == null ? void 0 : _a.disableLlmUiTransform) === true;
7830
+ const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
6887
7831
  if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
6888
7832
  return UITransformer.transform(question, sources, this.config, cachedSchema);
6889
7833
  }
@@ -6901,9 +7845,9 @@ ${context}`;
6901
7845
  const value = this.resolveNumericPredicateValue(source, predicate);
6902
7846
  return value !== null && this.matchesNumericPredicate(value, predicate);
6903
7847
  })).sort((a, b) => {
6904
- var _a, _b;
7848
+ var _a2, _b;
6905
7849
  const primary = predicates[0];
6906
- const aValue = (_a = this.resolveNumericPredicateValue(a, primary)) != null ? _a : 0;
7850
+ const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
6907
7851
  const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
6908
7852
  return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
6909
7853
  });
@@ -6975,8 +7919,8 @@ ${context}`;
6975
7919
  return Number.isFinite(numeric) ? numeric : null;
6976
7920
  }
6977
7921
  async retrieve(query, options) {
6978
- var _a, _b, _c, _d, _e, _f, _g;
6979
- const ns = (_a = options.namespace) != null ? _a : this.config.projectId;
7922
+ var _a2, _b, _c, _d, _e, _f, _g2;
7923
+ const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
6980
7924
  const topK = (_b = options.topK) != null ? _b : 5;
6981
7925
  const cacheKey = `${ns}::${query}`;
6982
7926
  let queryVector = this.embeddingCache.get(cacheKey);
@@ -7008,7 +7952,7 @@ ${context}`;
7008
7952
  ) : [];
7009
7953
  const resolvedSources = [];
7010
7954
  for (const source of sources) {
7011
- const parentId = (_g = source.metadata) == null ? void 0 : _g.parent_id;
7955
+ const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
7012
7956
  if (parentId) {
7013
7957
  console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
7014
7958
  resolvedSources.push(source);
@@ -7186,14 +8130,142 @@ var ProviderHealthCheck = class {
7186
8130
  }
7187
8131
  };
7188
8132
 
8133
+ // src/core/LicenseVerifier.ts
8134
+ var crypto2 = __toESM(require("crypto"));
8135
+ var LicenseVerifier = class {
8136
+ /**
8137
+ * Decodes, verifies signature, and checks metadata of a license key.
8138
+ *
8139
+ * @param licenseKey - Base64url signed JWT license key.
8140
+ * @param currentProjectId - Project namespace ID.
8141
+ * @param publicKeyOverride - Optional override for unit/integration tests.
8142
+ */
8143
+ static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
8144
+ const isProduction = process.env.NODE_ENV === "production";
8145
+ if (!licenseKey) {
8146
+ if (isProduction) {
8147
+ throw new ConfigurationException(
8148
+ "[Retrivora SDK] License key (licenseKey) is required in production environments."
8149
+ );
8150
+ }
8151
+ console.warn(
8152
+ `\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
8153
+ );
8154
+ return {
8155
+ projectId: currentProjectId,
8156
+ expiresAt: Math.floor(Date.now() / 1e3) + 86400,
8157
+ // Valid for 24h
8158
+ tier: "hobby"
8159
+ };
8160
+ }
8161
+ try {
8162
+ const parts = licenseKey.split(".");
8163
+ if (parts.length !== 3) {
8164
+ throw new Error("Malformed token structure (expected 3 parts).");
8165
+ }
8166
+ const [headerB64, payloadB64, signatureB64] = parts;
8167
+ const dataToVerify = `${headerB64}.${payloadB64}`;
8168
+ const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
8169
+ const signature = Buffer.from(signatureB64, "base64url");
8170
+ const data = Buffer.from(dataToVerify);
8171
+ const isValid = crypto2.verify(
8172
+ "sha256",
8173
+ data,
8174
+ publicKey,
8175
+ signature
8176
+ );
8177
+ if (!isValid) {
8178
+ throw new Error("Signature verification failed.");
8179
+ }
8180
+ const payload = JSON.parse(
8181
+ Buffer.from(payloadB64, "base64url").toString("utf8")
8182
+ );
8183
+ if (!payload.projectId) {
8184
+ throw new Error('License payload is missing "projectId".');
8185
+ }
8186
+ if (payload.projectId !== currentProjectId) {
8187
+ throw new Error(
8188
+ `Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
8189
+ );
8190
+ }
8191
+ if (!payload.expiresAt) {
8192
+ throw new Error('License payload is missing expiration ("expiresAt").');
8193
+ }
8194
+ const currentTimestampSec = Math.floor(Date.now() / 1e3);
8195
+ if (currentTimestampSec > payload.expiresAt) {
8196
+ throw new Error(
8197
+ `License key has expired. Expiration: ${new Date(
8198
+ payload.expiresAt * 1e3
8199
+ ).toDateString()}`
8200
+ );
8201
+ }
8202
+ if (isProduction && provider) {
8203
+ const tier = (payload.tier || "").toLowerCase();
8204
+ const normalizedProvider = provider.toLowerCase();
8205
+ if (tier === "hobby") {
8206
+ const allowedHobby = ["postgresql", "pgvector", "supabase"];
8207
+ if (!allowedHobby.includes(normalizedProvider)) {
8208
+ throw new Error(
8209
+ `The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
8210
+ );
8211
+ }
8212
+ } else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
8213
+ const allowedPro = [
8214
+ "postgresql",
8215
+ "pgvector",
8216
+ "supabase",
8217
+ "pinecone",
8218
+ "qdrant",
8219
+ "mongodb",
8220
+ "milvus",
8221
+ "chroma",
8222
+ "chromadb"
8223
+ ];
8224
+ if (!allowedPro.includes(normalizedProvider)) {
8225
+ throw new Error(
8226
+ `The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
8227
+ );
8228
+ }
8229
+ }
8230
+ }
8231
+ return payload;
8232
+ } catch (err) {
8233
+ const message = err instanceof Error ? err.message : String(err);
8234
+ throw new ConfigurationException(
8235
+ `[Retrivora SDK] License key validation failed: ${message}`
8236
+ );
8237
+ }
8238
+ }
8239
+ };
8240
+ // Retrivora's Public Key used to verify the license key signature.
8241
+ // In production, this matches the private key held by Retrivora SaaS.
8242
+ LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
8243
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
8244
+ XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
8245
+ xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
8246
+ NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
8247
+ iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
8248
+ +Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
8249
+ MwIDAQAB
8250
+ -----END PUBLIC KEY-----`;
8251
+
7189
8252
  // src/core/VectorPlugin.ts
7190
8253
  var VectorPlugin = class {
7191
8254
  constructor(hostConfig) {
7192
- this.config = ConfigResolver.resolve(hostConfig);
7193
- this.validationPromise = ConfigValidator.validateAndThrow(this.config);
8255
+ const resolvedConfig = ConfigResolver.resolve(hostConfig);
8256
+ this.config = resolvedConfig;
8257
+ this.validationPromise = (async () => {
8258
+ var _a2;
8259
+ await ConfigValidator.validateAndThrow(resolvedConfig);
8260
+ LicenseVerifier.verify(
8261
+ resolvedConfig.licenseKey,
8262
+ resolvedConfig.projectId,
8263
+ (_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
8264
+ );
8265
+ })();
7194
8266
  this.validationPromise.catch(() => {
7195
8267
  });
7196
- this.pipeline = new Pipeline(this.config);
8268
+ this.pipeline = new Pipeline(resolvedConfig);
7197
8269
  }
7198
8270
  /**
7199
8271
  * Get the current resolved configuration.
@@ -7322,8 +8394,8 @@ var DocumentParser = class {
7322
8394
  * Extract text from a File or Buffer based on its type.
7323
8395
  */
7324
8396
  static async parse(file, fileName, mimeType) {
7325
- var _a;
7326
- const extension = (_a = fileName.split(".").pop()) == null ? void 0 : _a.toLowerCase();
8397
+ var _a2;
8398
+ const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
7327
8399
  if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
7328
8400
  return this.readAsText(file);
7329
8401
  }
@@ -7375,7 +8447,496 @@ var DocumentParser = class {
7375
8447
  }
7376
8448
  };
7377
8449
 
8450
+ // src/core/DatabaseStorage.ts
8451
+ var fs = __toESM(require("fs"));
8452
+ var path = __toESM(require("path"));
8453
+ var DatabaseStorage = class {
8454
+ constructor(config) {
8455
+ // Dynamic PG Pool
8456
+ this.pgPool = null;
8457
+ // Dynamic MongoDB Client
8458
+ this.mongoClient = null;
8459
+ this.mongoDbName = "";
8460
+ // Filesystem fallback configuration
8461
+ this.fallbackDir = path.join(process.cwd(), ".retrivora");
8462
+ this.historyFile = path.join(this.fallbackDir, "history.json");
8463
+ this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
8464
+ var _a2, _b, _c, _d, _e;
8465
+ this.config = config;
8466
+ this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
8467
+ const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
8468
+ const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
8469
+ this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
8470
+ this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
8471
+ }
8472
+ /**
8473
+ * Asserts the user is running a valid Premium/Enterprise license in production.
8474
+ * In non-production (development / test) environments this is a complete no-op —
8475
+ * all History and Feedback features are freely accessible for local development.
8476
+ */
8477
+ checkPremiumSubscription() {
8478
+ if (process.env.NODE_ENV !== "production") {
8479
+ return;
8480
+ }
8481
+ if (!this.config.licenseKey) {
8482
+ throw new Error(
8483
+ "[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
8484
+ );
8485
+ }
8486
+ try {
8487
+ const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
8488
+ const tier = (payload.tier || "").toLowerCase();
8489
+ if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
8490
+ throw new Error(
8491
+ `[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
8492
+ );
8493
+ }
8494
+ } catch (err) {
8495
+ throw new Error(
8496
+ `[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
8497
+ );
8498
+ }
8499
+ }
8500
+ checkHistoryEnabled() {
8501
+ var _a2, _b;
8502
+ this.checkPremiumSubscription();
8503
+ if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
8504
+ throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
8505
+ }
8506
+ }
8507
+ checkFeedbackEnabled() {
8508
+ var _a2, _b;
8509
+ this.checkPremiumSubscription();
8510
+ if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
8511
+ throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
8512
+ }
8513
+ }
8514
+ async getPGPool() {
8515
+ const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
8516
+ const _g2 = global;
8517
+ if (_g2[globalKey]) {
8518
+ this.pgPool = _g2[globalKey];
8519
+ return this.pgPool;
8520
+ }
8521
+ const opts = this.config.vectorDb.options;
8522
+ if (!opts.connectionString) {
8523
+ throw new Error("[DatabaseStorage] pg connectionString option is missing.");
8524
+ }
8525
+ const { Pool: Pool3 } = await import("pg");
8526
+ this.pgPool = new Pool3({ connectionString: opts.connectionString });
8527
+ _g2[globalKey] = this.pgPool;
8528
+ const client = await this.pgPool.connect();
8529
+ try {
8530
+ await client.query(`
8531
+ CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
8532
+ id TEXT PRIMARY KEY,
8533
+ session_id TEXT NOT NULL,
8534
+ role TEXT NOT NULL,
8535
+ content TEXT NOT NULL,
8536
+ sources JSONB,
8537
+ ui_transformation JSONB,
8538
+ trace JSONB,
8539
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
8540
+ )
8541
+ `);
8542
+ await client.query(`
8543
+ CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
8544
+ id TEXT PRIMARY KEY,
8545
+ message_id TEXT NOT NULL UNIQUE,
8546
+ session_id TEXT NOT NULL,
8547
+ rating TEXT NOT NULL,
8548
+ comment TEXT,
8549
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
8550
+ )
8551
+ `);
8552
+ } finally {
8553
+ client.release();
8554
+ }
8555
+ return this.pgPool;
8556
+ }
8557
+ async getMongoClient() {
8558
+ const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
8559
+ const _g2 = global;
8560
+ if (_g2[globalKey]) {
8561
+ this.mongoClient = _g2[globalKey];
8562
+ this.mongoDbName = this.config.vectorDb.options.database;
8563
+ return this.mongoClient;
8564
+ }
8565
+ const opts = this.config.vectorDb.options;
8566
+ if (!opts.uri || !opts.database) {
8567
+ throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
8568
+ }
8569
+ const { MongoClient: MongoClient2 } = await import("mongodb");
8570
+ this.mongoClient = new MongoClient2(opts.uri);
8571
+ await this.mongoClient.connect();
8572
+ _g2[globalKey] = this.mongoClient;
8573
+ this.mongoDbName = opts.database;
8574
+ return this.mongoClient;
8575
+ }
8576
+ getMongoDb() {
8577
+ return this.mongoClient.db(this.mongoDbName);
8578
+ }
8579
+ // Helper for FS fallback reads
8580
+ readLocalFile(filePath) {
8581
+ if (!fs.existsSync(filePath)) return [];
8582
+ try {
8583
+ const raw = fs.readFileSync(filePath, "utf-8");
8584
+ return JSON.parse(raw) || [];
8585
+ } catch (e) {
8586
+ return [];
8587
+ }
8588
+ }
8589
+ // Helper for FS fallback writes
8590
+ writeLocalFile(filePath, data) {
8591
+ if (!fs.existsSync(this.fallbackDir)) {
8592
+ fs.mkdirSync(this.fallbackDir, { recursive: true });
8593
+ }
8594
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
8595
+ }
8596
+ // ─── Message History Operations ──────────────────────────────────────────
8597
+ async saveMessage(sessionId, message) {
8598
+ this.checkHistoryEnabled();
8599
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
8600
+ const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
8601
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8602
+ const pool = await this.getPGPool();
8603
+ await pool.query(
8604
+ `INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
8605
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
8606
+ ON CONFLICT (id) DO UPDATE
8607
+ SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
8608
+ [
8609
+ msgId,
8610
+ sessionId,
8611
+ message.role,
8612
+ message.content,
8613
+ message.sources ? JSON.stringify(message.sources) : null,
8614
+ message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
8615
+ message.trace ? JSON.stringify(message.trace) : null,
8616
+ createdAt
8617
+ ]
8618
+ );
8619
+ } else if (this.provider === "mongodb") {
8620
+ await this.getMongoClient();
8621
+ const db = this.getMongoDb();
8622
+ const col = db.collection(this.historyTableName);
8623
+ await col.updateOne(
8624
+ { id: msgId },
8625
+ {
8626
+ $set: {
8627
+ id: msgId,
8628
+ session_id: sessionId,
8629
+ role: message.role,
8630
+ content: message.content,
8631
+ sources: message.sources || null,
8632
+ ui_transformation: message.uiTransformation || null,
8633
+ trace: message.trace || null,
8634
+ created_at: createdAt
8635
+ }
8636
+ },
8637
+ { upsert: true }
8638
+ );
8639
+ } else {
8640
+ const history = this.readLocalFile(this.historyFile);
8641
+ const index = history.findIndex((h) => h.id === msgId);
8642
+ const item = {
8643
+ id: msgId,
8644
+ session_id: sessionId,
8645
+ role: message.role,
8646
+ content: message.content,
8647
+ sources: message.sources || null,
8648
+ ui_transformation: message.uiTransformation || null,
8649
+ trace: message.trace || null,
8650
+ created_at: createdAt
8651
+ };
8652
+ if (index !== -1) {
8653
+ history[index] = item;
8654
+ } else {
8655
+ history.push(item);
8656
+ }
8657
+ this.writeLocalFile(this.historyFile, history);
8658
+ }
8659
+ }
8660
+ async getHistory(sessionId) {
8661
+ this.checkHistoryEnabled();
8662
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8663
+ const pool = await this.getPGPool();
8664
+ const res = await pool.query(
8665
+ `SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
8666
+ FROM ${this.historyTableName}
8667
+ WHERE session_id = $1
8668
+ ORDER BY created_at ASC`,
8669
+ [sessionId]
8670
+ );
8671
+ return res.rows;
8672
+ } else if (this.provider === "mongodb") {
8673
+ await this.getMongoClient();
8674
+ const db = this.getMongoDb();
8675
+ const col = db.collection(this.historyTableName);
8676
+ const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
8677
+ return items.map((item) => ({
8678
+ id: item.id,
8679
+ role: item.role,
8680
+ content: item.content,
8681
+ sources: item.sources,
8682
+ uiTransformation: item.ui_transformation,
8683
+ trace: item.trace,
8684
+ createdAt: item.created_at
8685
+ }));
8686
+ } else {
8687
+ const history = this.readLocalFile(this.historyFile);
8688
+ return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
8689
+ }
8690
+ }
8691
+ async clearHistory(sessionId) {
8692
+ this.checkHistoryEnabled();
8693
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8694
+ const pool = await this.getPGPool();
8695
+ await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
8696
+ await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
8697
+ } else if (this.provider === "mongodb") {
8698
+ await this.getMongoClient();
8699
+ const db = this.getMongoDb();
8700
+ await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
8701
+ await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
8702
+ } else {
8703
+ const history = this.readLocalFile(this.historyFile);
8704
+ const filteredHistory = history.filter((h) => h.session_id !== sessionId);
8705
+ this.writeLocalFile(this.historyFile, filteredHistory);
8706
+ const feedback = this.readLocalFile(this.feedbackFile);
8707
+ const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
8708
+ this.writeLocalFile(this.feedbackFile, filteredFeedback);
8709
+ }
8710
+ }
8711
+ async listSessions() {
8712
+ this.checkHistoryEnabled();
8713
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8714
+ const pool = await this.getPGPool();
8715
+ const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
8716
+ return res.rows.map((r) => r.session_id);
8717
+ } else if (this.provider === "mongodb") {
8718
+ await this.getMongoClient();
8719
+ const db = this.getMongoDb();
8720
+ return db.collection(this.historyTableName).distinct("session_id");
8721
+ } else {
8722
+ const history = this.readLocalFile(this.historyFile);
8723
+ const sessions = new Set(history.map((h) => h.session_id));
8724
+ return Array.from(sessions);
8725
+ }
8726
+ }
8727
+ // ─── Feedback Operations ──────────────────────────────────────────────────
8728
+ async saveFeedback(feedback) {
8729
+ this.checkFeedbackEnabled();
8730
+ const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
8731
+ const createdAt = (/* @__PURE__ */ new Date()).toISOString();
8732
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8733
+ const pool = await this.getPGPool();
8734
+ await pool.query(
8735
+ `INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
8736
+ VALUES ($1, $2, $3, $4, $5, $6)
8737
+ ON CONFLICT (message_id) DO UPDATE
8738
+ SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
8739
+ [id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
8740
+ );
8741
+ } else if (this.provider === "mongodb") {
8742
+ await this.getMongoClient();
8743
+ const db = this.getMongoDb();
8744
+ const col = db.collection(this.feedbackTableName);
8745
+ await col.updateOne(
8746
+ { message_id: feedback.messageId },
8747
+ {
8748
+ $set: {
8749
+ id,
8750
+ message_id: feedback.messageId,
8751
+ session_id: feedback.sessionId,
8752
+ rating: feedback.rating,
8753
+ comment: feedback.comment || null,
8754
+ created_at: createdAt
8755
+ }
8756
+ },
8757
+ { upsert: true }
8758
+ );
8759
+ } else {
8760
+ const list = this.readLocalFile(this.feedbackFile);
8761
+ const index = list.findIndex((f) => f.message_id === feedback.messageId);
8762
+ const item = {
8763
+ id,
8764
+ message_id: feedback.messageId,
8765
+ session_id: feedback.sessionId,
8766
+ rating: feedback.rating,
8767
+ comment: feedback.comment || null,
8768
+ created_at: createdAt
8769
+ };
8770
+ if (index !== -1) {
8771
+ list[index] = item;
8772
+ } else {
8773
+ list.push(item);
8774
+ }
8775
+ this.writeLocalFile(this.feedbackFile, list);
8776
+ }
8777
+ }
8778
+ async getFeedback(messageId) {
8779
+ this.checkFeedbackEnabled();
8780
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8781
+ const pool = await this.getPGPool();
8782
+ const res = await pool.query(
8783
+ `SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
8784
+ FROM ${this.feedbackTableName}
8785
+ WHERE message_id = $1`,
8786
+ [messageId]
8787
+ );
8788
+ return res.rows[0] || null;
8789
+ } else if (this.provider === "mongodb") {
8790
+ await this.getMongoClient();
8791
+ const db = this.getMongoDb();
8792
+ const col = db.collection(this.feedbackTableName);
8793
+ const item = await col.findOne({ message_id: messageId });
8794
+ if (!item) return null;
8795
+ return {
8796
+ id: item.id,
8797
+ messageId: item.message_id,
8798
+ sessionId: item.session_id,
8799
+ rating: item.rating,
8800
+ comment: item.comment,
8801
+ createdAt: item.created_at
8802
+ };
8803
+ } else {
8804
+ const list = this.readLocalFile(this.feedbackFile);
8805
+ return list.find((f) => f.message_id === messageId) || null;
8806
+ }
8807
+ }
8808
+ async listFeedback() {
8809
+ this.checkFeedbackEnabled();
8810
+ if (this.provider === "postgresql" || this.provider === "pgvector") {
8811
+ const pool = await this.getPGPool();
8812
+ const res = await pool.query(
8813
+ `SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
8814
+ FROM ${this.feedbackTableName}
8815
+ ORDER BY created_at DESC`
8816
+ );
8817
+ return res.rows;
8818
+ } else if (this.provider === "mongodb") {
8819
+ await this.getMongoClient();
8820
+ const db = this.getMongoDb();
8821
+ const col = db.collection(this.feedbackTableName);
8822
+ const items = await col.find({}).sort({ created_at: -1 }).toArray();
8823
+ return items.map((item) => ({
8824
+ id: item.id,
8825
+ messageId: item.message_id,
8826
+ sessionId: item.session_id,
8827
+ rating: item.rating,
8828
+ comment: item.comment,
8829
+ createdAt: item.created_at
8830
+ }));
8831
+ } else {
8832
+ const list = this.readLocalFile(this.feedbackFile);
8833
+ return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
8834
+ }
8835
+ }
8836
+ async disconnect() {
8837
+ if (this.pgPool) {
8838
+ await this.pgPool.end();
8839
+ this.pgPool = null;
8840
+ }
8841
+ if (this.mongoClient) {
8842
+ await this.mongoClient.close();
8843
+ this.mongoClient = null;
8844
+ }
8845
+ }
8846
+ };
8847
+
7378
8848
  // src/handlers/index.ts
8849
+ async function checkAuth(req, onAuthorize) {
8850
+ if (!onAuthorize) return null;
8851
+ try {
8852
+ const res = await onAuthorize(req);
8853
+ if (res === false) {
8854
+ return import_server.NextResponse.json({ error: "Unauthorized" }, { status: 401 });
8855
+ }
8856
+ if (res instanceof Response) {
8857
+ return res;
8858
+ }
8859
+ return null;
8860
+ } catch (err) {
8861
+ const msg = err instanceof Error ? err.message : "Authorization check failed";
8862
+ return import_server.NextResponse.json({ error: msg }, { status: 401 });
8863
+ }
8864
+ }
8865
+ var RateLimiter = class {
8866
+ constructor(windowMs = 6e4, max = 30) {
8867
+ this.hits = /* @__PURE__ */ new Map();
8868
+ this.windowMs = windowMs;
8869
+ this.max = max;
8870
+ }
8871
+ /** Returns true if the request should be allowed, false if rate-limited. */
8872
+ allow(key) {
8873
+ const now = Date.now();
8874
+ const cutoff = now - this.windowMs;
8875
+ const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
8876
+ existing.push(now);
8877
+ this.hits.set(key, existing);
8878
+ if (this.hits.size > 5e3) {
8879
+ for (const [k, timestamps] of this.hits.entries()) {
8880
+ if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
8881
+ }
8882
+ }
8883
+ return existing.length <= this.max;
8884
+ }
8885
+ retryAfterSec(key) {
8886
+ const now = Date.now();
8887
+ const cutoff = now - this.windowMs;
8888
+ const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
8889
+ if (existing.length === 0) return 0;
8890
+ return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
8891
+ }
8892
+ };
8893
+ var _g = global;
8894
+ var _a;
8895
+ var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
8896
+ function getRateLimitKey(req) {
8897
+ var _a2, _b;
8898
+ const ip = ((_b = (_a2 = req.headers.get("x-forwarded-for")) == null ? void 0 : _a2.split(",")[0]) == null ? void 0 : _b.trim()) || req.headers.get("x-real-ip") || "127.0.0.1";
8899
+ return `ip:${ip}`;
8900
+ }
8901
+ function checkRateLimit(req) {
8902
+ const key = getRateLimitKey(req);
8903
+ if (!rateLimiter.allow(key)) {
8904
+ const retryAfter = rateLimiter.retryAfterSec(key);
8905
+ return new Response(
8906
+ JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
8907
+ {
8908
+ status: 429,
8909
+ headers: {
8910
+ "Content-Type": "application/json",
8911
+ "Retry-After": String(retryAfter),
8912
+ "X-RateLimit-Limit": "30",
8913
+ "X-RateLimit-Window": "60"
8914
+ }
8915
+ }
8916
+ );
8917
+ }
8918
+ return null;
8919
+ }
8920
+ var MAX_MESSAGE_LENGTH = 8e3;
8921
+ function sanitizeInput(raw) {
8922
+ const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
8923
+ const trimmed = stripped.trim();
8924
+ if (!trimmed) {
8925
+ return { ok: false, error: "message must not be empty" };
8926
+ }
8927
+ if (trimmed.length > MAX_MESSAGE_LENGTH) {
8928
+ return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
8929
+ }
8930
+ return { ok: true, value: trimmed };
8931
+ }
8932
+ function getOrCreatePlugin(configOrPlugin) {
8933
+ if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
8934
+ const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
8935
+ if (!_g[cacheKey]) {
8936
+ _g[cacheKey] = new VectorPlugin(configOrPlugin);
8937
+ }
8938
+ return _g[cacheKey];
8939
+ }
7379
8940
  function sseFrame(payload) {
7380
8941
  return `data: ${JSON.stringify(payload)}
7381
8942
 
@@ -7413,47 +8974,88 @@ var SSE_HEADERS = {
7413
8974
  "X-Accel-Buffering": "no"
7414
8975
  // Disable Nginx buffering for streaming
7415
8976
  };
7416
- function createChatHandler(configOrPlugin) {
7417
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
8977
+ function createChatHandler(configOrPlugin, options) {
8978
+ const plugin = getOrCreatePlugin(configOrPlugin);
8979
+ const storage = new DatabaseStorage(plugin.getConfig());
8980
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
7418
8981
  return async function POST(req) {
8982
+ const authResult = await checkAuth(req, onAuthorize);
8983
+ if (authResult) return authResult;
8984
+ const rateLimited = checkRateLimit(req);
8985
+ if (rateLimited) return rateLimited;
7419
8986
  try {
7420
8987
  const body = await req.json();
7421
- const { message, history = [], namespace } = body;
7422
- if (!(message == null ? void 0 : message.trim())) {
7423
- return import_server.NextResponse.json({ error: "message is required" }, { status: 400 });
7424
- }
8988
+ const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
8989
+ const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
8990
+ if (!sanitized.ok) {
8991
+ return import_server.NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
8992
+ }
8993
+ const message = sanitized.value;
8994
+ const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
8995
+ await storage.saveMessage(sessionId, {
8996
+ id: userMsgId,
8997
+ role: "user",
8998
+ content: message
8999
+ }).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
7425
9000
  const result = await plugin.chat(message, history, namespace);
7426
- return import_server.NextResponse.json(result);
9001
+ const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
9002
+ await storage.saveMessage(sessionId, {
9003
+ id: assistantMsgId,
9004
+ role: "assistant",
9005
+ content: result.reply,
9006
+ sources: result.sources,
9007
+ uiTransformation: result.ui_transformation,
9008
+ trace: result.trace
9009
+ }).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
9010
+ return import_server.NextResponse.json(__spreadProps(__spreadValues({}, result), {
9011
+ messageId: assistantMsgId,
9012
+ userMessageId: userMsgId
9013
+ }));
7427
9014
  } catch (err) {
7428
9015
  const message = err instanceof Error ? err.message : "Internal server error";
7429
9016
  return import_server.NextResponse.json({ error: message }, { status: 500 });
7430
9017
  }
7431
9018
  };
7432
9019
  }
7433
- function createStreamHandler(configOrPlugin) {
7434
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
9020
+ function createStreamHandler(configOrPlugin, options) {
9021
+ const plugin = getOrCreatePlugin(configOrPlugin);
9022
+ const storage = new DatabaseStorage(plugin.getConfig());
9023
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
7435
9024
  return async function POST(req) {
9025
+ const authResult = await checkAuth(req, onAuthorize);
9026
+ if (authResult) return authResult;
9027
+ const rateLimited = checkRateLimit(req);
9028
+ if (rateLimited) return rateLimited;
7436
9029
  let body;
7437
9030
  try {
7438
9031
  body = await req.json();
7439
9032
  } catch (e) {
7440
- return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
9033
+ return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
7441
9034
  status: 400,
7442
9035
  headers: { "Content-Type": "application/json" }
7443
9036
  });
7444
9037
  }
7445
- const { message, history = [], namespace } = body;
7446
- if (!(message == null ? void 0 : message.trim())) {
7447
- return new Response(JSON.stringify({ error: "message is required" }), {
7448
- status: 400,
7449
- headers: { "Content-Type": "application/json" }
7450
- });
9038
+ const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
9039
+ const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
9040
+ if (!sanitized.ok) {
9041
+ return new Response(
9042
+ JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
9043
+ { status: 400, headers: { "Content-Type": "application/json" } }
9044
+ );
7451
9045
  }
9046
+ const message = sanitized.value;
9047
+ const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
9048
+ await storage.saveMessage(sessionId, {
9049
+ id: userMsgId,
9050
+ role: "user",
9051
+ content: message
9052
+ }).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
9053
+ const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
7452
9054
  const encoder = new TextEncoder();
7453
9055
  let isActive = true;
7454
9056
  const stream = new ReadableStream({
7455
9057
  async start(controller) {
7456
- var _a;
9058
+ var _a2;
7457
9059
  const enqueue = (text) => {
7458
9060
  if (!isActive) return;
7459
9061
  try {
@@ -7464,11 +9066,13 @@ function createStreamHandler(configOrPlugin) {
7464
9066
  };
7465
9067
  try {
7466
9068
  const pipelineStream = plugin.chatStream(message, history, namespace);
9069
+ let fullReply = "";
7467
9070
  try {
7468
9071
  for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
7469
9072
  const chunk = temp.value;
7470
9073
  if (!isActive) break;
7471
9074
  if (typeof chunk === "string") {
9075
+ fullReply += chunk;
7472
9076
  enqueue(sseTextFrame(chunk));
7473
9077
  } else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
7474
9078
  enqueue(`data: ${JSON.stringify(chunk)}
@@ -7481,9 +9085,10 @@ function createStreamHandler(configOrPlugin) {
7481
9085
  if (responseChunk == null ? void 0 : responseChunk.trace) {
7482
9086
  enqueue(sseObservabilityFrame(responseChunk.trace));
7483
9087
  }
9088
+ let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
7484
9089
  if (sources.length > 0) {
7485
9090
  try {
7486
- const uiTransformation = (_a = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a : UITransformer.transform(message, sources, plugin.getConfig());
9091
+ uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
7487
9092
  if (uiTransformation) {
7488
9093
  enqueue(sseUIFrame(uiTransformation));
7489
9094
  }
@@ -7491,11 +9096,22 @@ function createStreamHandler(configOrPlugin) {
7491
9096
  console.warn("[createStreamHandler] UI transformation warning:", transformError);
7492
9097
  try {
7493
9098
  const fallback = UITransformer.transform(message, sources, plugin.getConfig());
7494
- if (fallback) enqueue(sseUIFrame(fallback));
9099
+ if (fallback) {
9100
+ uiTransformation = fallback;
9101
+ enqueue(sseUIFrame(fallback));
9102
+ }
7495
9103
  } catch (e) {
7496
9104
  }
7497
9105
  }
7498
9106
  }
9107
+ await storage.saveMessage(sessionId, {
9108
+ id: assistantMsgId,
9109
+ role: "assistant",
9110
+ content: fullReply,
9111
+ sources,
9112
+ uiTransformation,
9113
+ trace: responseChunk == null ? void 0 : responseChunk.trace
9114
+ }).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
7499
9115
  }
7500
9116
  }
7501
9117
  } catch (temp) {
@@ -7532,12 +9148,15 @@ function createStreamHandler(configOrPlugin) {
7532
9148
  console.log("[createStreamHandler] Stream connection closed by client:", reason);
7533
9149
  }
7534
9150
  });
7535
- return new Response(stream, { headers: SSE_HEADERS });
9151
+ return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
7536
9152
  };
7537
9153
  }
7538
- function createIngestHandler(configOrPlugin) {
7539
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
9154
+ function createIngestHandler(configOrPlugin, options) {
9155
+ const plugin = getOrCreatePlugin(configOrPlugin);
9156
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
7540
9157
  return async function POST(req) {
9158
+ const authResult = await checkAuth(req, onAuthorize);
9159
+ if (authResult) return authResult;
7541
9160
  try {
7542
9161
  const body = await req.json();
7543
9162
  const { documents, namespace } = body;
@@ -7552,9 +9171,14 @@ function createIngestHandler(configOrPlugin) {
7552
9171
  }
7553
9172
  };
7554
9173
  }
7555
- function createHealthHandler(configOrPlugin) {
7556
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
7557
- return async function GET() {
9174
+ function createHealthHandler(configOrPlugin, options) {
9175
+ const plugin = getOrCreatePlugin(configOrPlugin);
9176
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
9177
+ return async function GET(req) {
9178
+ if (req) {
9179
+ const authResult = await checkAuth(req, onAuthorize);
9180
+ if (authResult) return authResult;
9181
+ }
7558
9182
  try {
7559
9183
  const health = await plugin.checkHealth();
7560
9184
  const status = health.allHealthy ? "ok" : "degraded";
@@ -7569,9 +9193,12 @@ function createHealthHandler(configOrPlugin) {
7569
9193
  }
7570
9194
  };
7571
9195
  }
7572
- function createUploadHandler(configOrPlugin) {
7573
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
9196
+ function createUploadHandler(configOrPlugin, options) {
9197
+ const plugin = getOrCreatePlugin(configOrPlugin);
9198
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
7574
9199
  return async function POST(req) {
9200
+ const authResult = await checkAuth(req, onAuthorize);
9201
+ if (authResult) return authResult;
7575
9202
  try {
7576
9203
  const formData = await req.formData();
7577
9204
  const files = formData.getAll("files");
@@ -7645,9 +9272,12 @@ function createUploadHandler(configOrPlugin) {
7645
9272
  }
7646
9273
  };
7647
9274
  }
7648
- function createSuggestionsHandler(configOrPlugin) {
7649
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
9275
+ function createSuggestionsHandler(configOrPlugin, options) {
9276
+ const plugin = getOrCreatePlugin(configOrPlugin);
9277
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
7650
9278
  return async function POST(req) {
9279
+ const authResult = await checkAuth(req, onAuthorize);
9280
+ if (authResult) return authResult;
7651
9281
  try {
7652
9282
  const body = await req.json();
7653
9283
  const { query, namespace } = body;
@@ -7662,13 +9292,108 @@ function createSuggestionsHandler(configOrPlugin) {
7662
9292
  }
7663
9293
  };
7664
9294
  }
7665
- function createRagHandler(configOrPlugin) {
7666
- const plugin = configOrPlugin instanceof VectorPlugin ? configOrPlugin : new VectorPlugin(configOrPlugin);
7667
- const chatHandler = createChatHandler(plugin);
7668
- const streamHandler = createStreamHandler(plugin);
7669
- const uploadHandler = createUploadHandler(plugin);
7670
- const healthHandler = createHealthHandler(plugin);
7671
- const suggestionsHandler = createSuggestionsHandler(plugin);
9295
+ function createHistoryHandler(configOrPlugin, options) {
9296
+ const plugin = getOrCreatePlugin(configOrPlugin);
9297
+ const storage = new DatabaseStorage(plugin.getConfig());
9298
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
9299
+ return async function handler(req) {
9300
+ const authResult = await checkAuth(req, onAuthorize);
9301
+ if (authResult) return authResult;
9302
+ const url = new URL(req.url);
9303
+ const sessionId = url.searchParams.get("sessionId") || "default";
9304
+ if (req.method === "GET") {
9305
+ try {
9306
+ const history = await storage.getHistory(sessionId);
9307
+ return import_server.NextResponse.json({ history });
9308
+ } catch (err) {
9309
+ const message = err instanceof Error ? err.message : "Failed to fetch history";
9310
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
9311
+ }
9312
+ } else if (req.method === "POST") {
9313
+ try {
9314
+ const body = await req.json().catch(() => ({}));
9315
+ const sid = body.sessionId || sessionId;
9316
+ await storage.clearHistory(sid);
9317
+ return import_server.NextResponse.json({ success: true });
9318
+ } catch (err) {
9319
+ const message = err instanceof Error ? err.message : "Failed to clear history";
9320
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
9321
+ }
9322
+ }
9323
+ return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
9324
+ };
9325
+ }
9326
+ function createFeedbackHandler(configOrPlugin, options) {
9327
+ const plugin = getOrCreatePlugin(configOrPlugin);
9328
+ const storage = new DatabaseStorage(plugin.getConfig());
9329
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
9330
+ return async function handler(req) {
9331
+ const authResult = await checkAuth(req, onAuthorize);
9332
+ if (authResult) return authResult;
9333
+ if (req.method === "GET") {
9334
+ try {
9335
+ const url = new URL(req.url);
9336
+ const messageId = url.searchParams.get("messageId");
9337
+ if (!messageId) {
9338
+ const feedbackList = await storage.listFeedback();
9339
+ return import_server.NextResponse.json({ feedback: feedbackList });
9340
+ }
9341
+ const feedback = await storage.getFeedback(messageId);
9342
+ return import_server.NextResponse.json({ feedback });
9343
+ } catch (err) {
9344
+ const message = err instanceof Error ? err.message : "Failed to fetch feedback";
9345
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
9346
+ }
9347
+ } else if (req.method === "POST") {
9348
+ try {
9349
+ const body = await req.json();
9350
+ const { messageId, sessionId = "default", rating, comment } = body;
9351
+ if (!messageId) {
9352
+ return import_server.NextResponse.json({ error: "messageId is required" }, { status: 400 });
9353
+ }
9354
+ if (!rating) {
9355
+ return import_server.NextResponse.json({ error: "rating is required" }, { status: 400 });
9356
+ }
9357
+ await storage.saveFeedback({ messageId, sessionId, rating, comment });
9358
+ return import_server.NextResponse.json({ success: true });
9359
+ } catch (err) {
9360
+ const message = err instanceof Error ? err.message : "Failed to save feedback";
9361
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
9362
+ }
9363
+ }
9364
+ return import_server.NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
9365
+ };
9366
+ }
9367
+ function createSessionsHandler(configOrPlugin, options) {
9368
+ const plugin = getOrCreatePlugin(configOrPlugin);
9369
+ const storage = new DatabaseStorage(plugin.getConfig());
9370
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
9371
+ return async function GET(req) {
9372
+ if (req) {
9373
+ const authResult = await checkAuth(req, onAuthorize);
9374
+ if (authResult) return authResult;
9375
+ }
9376
+ void req;
9377
+ try {
9378
+ const sessions = await storage.listSessions();
9379
+ return import_server.NextResponse.json({ sessions });
9380
+ } catch (err) {
9381
+ const message = err instanceof Error ? err.message : "Failed to list sessions";
9382
+ return import_server.NextResponse.json({ error: message }, { status: 500 });
9383
+ }
9384
+ };
9385
+ }
9386
+ function createRagHandler(configOrPlugin, options) {
9387
+ const plugin = getOrCreatePlugin(configOrPlugin);
9388
+ const onAuthorize = options == null ? void 0 : options.onAuthorize;
9389
+ const chatHandler = createChatHandler(plugin, { onAuthorize });
9390
+ const streamHandler = createStreamHandler(plugin, { onAuthorize });
9391
+ const uploadHandler = createUploadHandler(plugin, { onAuthorize });
9392
+ const healthHandler = createHealthHandler(plugin, { onAuthorize });
9393
+ const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
9394
+ const historyHandler = createHistoryHandler(plugin, { onAuthorize });
9395
+ const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
9396
+ const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
7672
9397
  async function routePostRequest(req, segment) {
7673
9398
  switch (segment) {
7674
9399
  case "chat":
@@ -7680,22 +9405,35 @@ function createRagHandler(configOrPlugin) {
7680
9405
  case "suggestions":
7681
9406
  return suggestionsHandler(req);
7682
9407
  case "health":
7683
- return healthHandler();
9408
+ return healthHandler(req);
9409
+ case "history":
9410
+ case "history/clear":
9411
+ return historyHandler(req);
9412
+ case "feedback":
9413
+ return feedbackHandler(req);
7684
9414
  default:
7685
9415
  return import_server.NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
7686
9416
  }
7687
9417
  }
7688
9418
  async function routeGetRequest(req, segment) {
7689
- if (segment === "health") {
7690
- return healthHandler();
9419
+ switch (segment) {
9420
+ case "health":
9421
+ return healthHandler(req);
9422
+ case "history":
9423
+ return historyHandler(req);
9424
+ case "feedback":
9425
+ return feedbackHandler(req);
9426
+ case "sessions":
9427
+ return sessionsHandler(req);
9428
+ default:
9429
+ return import_server.NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
7691
9430
  }
7692
- return import_server.NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
7693
9431
  }
7694
9432
  async function getSegment(context) {
7695
- var _a;
7696
- const resolvedParams = typeof ((_a = context == null ? void 0 : context.params) == null ? void 0 : _a.then) === "function" ? await context.params : context == null ? void 0 : context.params;
9433
+ var _a2;
9434
+ const resolvedParams = typeof ((_a2 = context == null ? void 0 : context.params) == null ? void 0 : _a2.then) === "function" ? await context.params : context == null ? void 0 : context.params;
7697
9435
  const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
7698
- return segments[0] || "chat";
9436
+ return segments.join("/") || "chat";
7699
9437
  }
7700
9438
  return {
7701
9439
  GET: async (req, context) => {
@@ -7721,9 +9459,12 @@ function createRagHandler(configOrPlugin) {
7721
9459
  // Annotate the CommonJS export names for ESM import in node:
7722
9460
  0 && (module.exports = {
7723
9461
  createChatHandler,
9462
+ createFeedbackHandler,
7724
9463
  createHealthHandler,
9464
+ createHistoryHandler,
7725
9465
  createIngestHandler,
7726
9466
  createRagHandler,
9467
+ createSessionsHandler,
7727
9468
  createStreamHandler,
7728
9469
  createSuggestionsHandler,
7729
9470
  createUploadHandler,