@retrivora-ai/rag-engine 1.9.1 → 1.9.3

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.
@@ -519,6 +519,82 @@ var init_PostgreSQLProvider = __esm({
519
519
  }
520
520
  });
521
521
 
522
+ // src/utils/synonyms.ts
523
+ function resolveMetadataValue(meta, uiKey) {
524
+ var _a;
525
+ const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
526
+ const keys = Object.keys(meta);
527
+ const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
528
+ let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
529
+ if (match !== void 0) return meta[match];
530
+ match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
531
+ if (match !== void 0) return meta[match];
532
+ const isBlacklisted = (kl) => {
533
+ return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
534
+ };
535
+ match = keys.find((k) => {
536
+ const kl = k.toLowerCase();
537
+ if (isBlacklisted(kl)) return false;
538
+ return kl.includes(uiKey.toLowerCase());
539
+ });
540
+ if (match !== void 0) return meta[match];
541
+ match = keys.find((k) => {
542
+ const kl = k.toLowerCase();
543
+ if (isBlacklisted(kl)) return false;
544
+ return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
545
+ });
546
+ return match !== void 0 ? meta[match] : void 0;
547
+ }
548
+ var FIELD_SYNONYMS;
549
+ var init_synonyms = __esm({
550
+ "src/utils/synonyms.ts"() {
551
+ "use strict";
552
+ FIELD_SYNONYMS = {
553
+ name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
554
+ price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd", "variant price"],
555
+ brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
556
+ image: [
557
+ "imageUrl",
558
+ "thumbnail",
559
+ "img",
560
+ "url",
561
+ "photo",
562
+ "picture",
563
+ "media",
564
+ "image_url",
565
+ "main_image",
566
+ "product_image",
567
+ "thumb",
568
+ "image src",
569
+ "variant image"
570
+ ],
571
+ stock: [
572
+ "inventory",
573
+ "quantity",
574
+ "count",
575
+ "availability",
576
+ "stock_level",
577
+ "inStock",
578
+ "is_available",
579
+ "in stock",
580
+ "status",
581
+ "variant inventory qty"
582
+ ],
583
+ category: [
584
+ "product_category",
585
+ "product category",
586
+ "category_name",
587
+ "category name",
588
+ "department",
589
+ "collection",
590
+ "type"
591
+ ],
592
+ description: ["summary", "content", "body", "text", "info", "details", "body (html)", "seo description"],
593
+ link: ["url", "href", "product_url", "page_url", "link"]
594
+ };
595
+ }
596
+ });
597
+
522
598
  // src/providers/vectordb/MultiTablePostgresProvider.ts
523
599
  var MultiTablePostgresProvider_exports = {};
524
600
  __export(MultiTablePostgresProvider_exports, {
@@ -530,6 +606,7 @@ var init_MultiTablePostgresProvider = __esm({
530
606
  "src/providers/vectordb/MultiTablePostgresProvider.ts"() {
531
607
  "use strict";
532
608
  init_BaseVectorProvider();
609
+ init_synonyms();
533
610
  MultiTablePostgresProvider = class extends BaseVectorProvider {
534
611
  constructor(config) {
535
612
  var _a, _b, _c;
@@ -610,8 +687,13 @@ var init_MultiTablePostgresProvider = __esm({
610
687
  }
611
688
  tableName = tableName.replace(/[^a-z0-9_]/gi, "_").toLowerCase() || this.uploadTable;
612
689
  const firstMeta = fileDocs[0].metadata || {};
613
- const systemKeys = ["fileName", "fileSize", "fileType", "uploadedAt", "dimension", "chunkIndex", "id", "namespace", "content", "metadata", "embedding"];
614
- const csvHeaders = Object.keys(firstMeta).filter((k) => !systemKeys.includes(k) && !systemKeys.includes(k.toLowerCase()));
690
+ let csvHeaders = [];
691
+ if (Array.isArray(firstMeta.csvHeaders)) {
692
+ csvHeaders = firstMeta.csvHeaders;
693
+ } else {
694
+ const systemKeys = ["fileName", "fileSize", "fileType", "uploadedAt", "dimension", "chunkIndex", "id", "namespace", "content", "metadata", "embedding", "docId", "docid", "chunkId", "chunkid", "csvHeaders", "csvheaders"];
695
+ csvHeaders = Object.keys(firstMeta).filter((k) => !systemKeys.includes(k) && !systemKeys.includes(k.toLowerCase()));
696
+ }
615
697
  const columnDefs = csvHeaders.map((h) => `"${h}" TEXT`).join(",\n ");
616
698
  const createTableSql = `
617
699
  CREATE TABLE IF NOT EXISTS "${tableName}" (
@@ -704,10 +786,26 @@ var init_MultiTablePostgresProvider = __esm({
704
786
  };
705
787
  const dynamicKeywordQuery = getDynamicKeywordQuery();
706
788
  const tableLimit = Math.max(topK, 50);
789
+ const metadataFilters = _filter == null ? void 0 : _filter.metadata;
707
790
  const queryPromises = this.tables.map(async (table) => {
708
791
  try {
709
792
  let sqlQuery = "";
710
793
  let params = [];
794
+ let whereClause = "";
795
+ const filterParams = [];
796
+ if (metadataFilters && Object.keys(metadataFilters).length > 0) {
797
+ const conditions = Object.entries(metadataFilters).map(([key, val]) => {
798
+ var _a3;
799
+ filterParams.push(String(val));
800
+ const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
801
+ const paramIdx = baseOffset + filterParams.length;
802
+ const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
803
+ const keysToCheck = [key, ...synonyms];
804
+ const coalesceExprs = keysToCheck.map((k) => `LOWER(metadata->>'${k}')`);
805
+ return `COALESCE(${coalesceExprs.join(", ")}) = LOWER($${paramIdx})`;
806
+ });
807
+ whereClause = `WHERE ${conditions.join(" AND ")}`;
808
+ }
711
809
  if (queryText && dynamicKeywordQuery) {
712
810
  const hasEntityHints = entityHints.length > 0;
713
811
  const exactNameScoreExpr = hasEntityHints ? `+ (
@@ -724,19 +822,21 @@ var init_MultiTablePostgresProvider = __esm({
724
822
  COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
725
823
  ((1 - (embedding <=> $1::vector)) + (COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) * 2.0) ${exactNameScoreExpr}) AS hybrid_score
726
824
  FROM "${table}" t
825
+ ${whereClause}
727
826
  ORDER BY hybrid_score DESC
728
827
  LIMIT ${tableLimit}
729
828
  `;
730
- params = [vectorLiteral, dynamicKeywordQuery];
829
+ params = [vectorLiteral, dynamicKeywordQuery, ...filterParams];
731
830
  } else {
732
831
  sqlQuery = `
733
832
  SELECT *,
734
833
  (1 - (embedding <=> $1::vector)) AS hybrid_score
735
834
  FROM "${table}" t
835
+ ${whereClause}
736
836
  ORDER BY hybrid_score DESC
737
837
  LIMIT ${tableLimit}
738
838
  `;
739
- params = [vectorLiteral];
839
+ params = [vectorLiteral, ...filterParams];
740
840
  }
741
841
  const result = await this.pool.query(sqlQuery, params);
742
842
  if (result.rowCount && result.rowCount > 0) {
@@ -969,12 +1069,15 @@ var init_MongoDBProvider = __esm({
969
1069
  }
970
1070
  );
971
1071
  const results = await this.collection.aggregate(pipeline).toArray();
972
- return results.map((res) => ({
973
- id: res._id,
974
- content: res[this.contentKey],
975
- metadata: res[this.metadataKey] || {},
976
- score: res.score
977
- }));
1072
+ return results.map((res) => {
1073
+ const normalizedScore = res.score * 2 - 1;
1074
+ return {
1075
+ id: res._id,
1076
+ content: res[this.contentKey],
1077
+ metadata: res[this.metadataKey] || {},
1078
+ score: normalizedScore
1079
+ };
1080
+ });
978
1081
  }
979
1082
  async delete(id, namespace) {
980
1083
  await this.collection.deleteOne(__spreadValues({ _id: id }, namespace ? { namespace } : {}));
@@ -4316,7 +4419,8 @@ var QueryProcessor = class {
4316
4419
  const fieldValuePatterns = [
4317
4420
  new RegExp(`\\b${fieldPattern}\\s*(?:=|:)\\s*["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4318
4421
  new RegExp(`\\b${fieldPattern}\\s+(?:is|are|was|were|equals?|equal to|named|called)\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4319
- new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
4422
+ new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4423
+ new RegExp(`\\b(?:under|in|for|from|of)\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
4320
4424
  ];
4321
4425
  for (const pattern of fieldValuePatterns) {
4322
4426
  for (const match of question.matchAll(pattern)) {
@@ -4550,73 +4654,8 @@ var LLMRouter = class {
4550
4654
  }
4551
4655
  };
4552
4656
 
4553
- // src/utils/synonyms.ts
4554
- var FIELD_SYNONYMS = {
4555
- name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
4556
- price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
4557
- brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
4558
- image: [
4559
- "imageUrl",
4560
- "thumbnail",
4561
- "img",
4562
- "url",
4563
- "photo",
4564
- "picture",
4565
- "media",
4566
- "image_url",
4567
- "main_image",
4568
- "product_image",
4569
- "thumb"
4570
- ],
4571
- stock: [
4572
- "inventory",
4573
- "quantity",
4574
- "count",
4575
- "availability",
4576
- "stock_level",
4577
- "inStock",
4578
- "is_available",
4579
- "in stock",
4580
- "status"
4581
- ],
4582
- category: [
4583
- "product_category",
4584
- "product category",
4585
- "category_name",
4586
- "category name",
4587
- "department",
4588
- "collection"
4589
- ],
4590
- description: ["summary", "content", "body", "text", "info", "details"],
4591
- link: ["url", "href", "product_url", "page_url", "link"]
4592
- };
4593
- function resolveMetadataValue(meta, uiKey) {
4594
- var _a;
4595
- const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
4596
- const keys = Object.keys(meta);
4597
- const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
4598
- let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
4599
- if (match !== void 0) return meta[match];
4600
- match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
4601
- if (match !== void 0) return meta[match];
4602
- const isBlacklisted = (kl) => {
4603
- return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
4604
- };
4605
- match = keys.find((k) => {
4606
- const kl = k.toLowerCase();
4607
- if (isBlacklisted(kl)) return false;
4608
- return kl.includes(uiKey.toLowerCase());
4609
- });
4610
- if (match !== void 0) return meta[match];
4611
- match = keys.find((k) => {
4612
- const kl = k.toLowerCase();
4613
- if (isBlacklisted(kl)) return false;
4614
- return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
4615
- });
4616
- return match !== void 0 ? meta[match] : void 0;
4617
- }
4618
-
4619
4657
  // src/utils/UITransformer.ts
4658
+ init_synonyms();
4620
4659
  var UITransformer = class {
4621
4660
  // ─── Public Entry Points ─────────────────────────────────────────────────
4622
4661
  /**
@@ -4913,7 +4952,7 @@ RULES:
4913
4952
  }
4914
4953
  // ─── Transform Helpers ────────────────────────────────────────────────────
4915
4954
  static transformToProductCarousel(data, config, trainedSchema) {
4916
- const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null);
4955
+ const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null).slice(0, 15);
4917
4956
  return {
4918
4957
  type: "product_carousel",
4919
4958
  title: "Recommended Products",
@@ -5872,14 +5911,16 @@ Given these metadata keys from a database: [${keys.join(", ")}]
5872
5911
  Identify which keys best correspond to these standard UI properties:
5873
5912
  ${propertyList}
5874
5913
 
5875
- Return ONLY a JSON object where the keys are the UI properties and the values are the matching database keys.
5914
+ Return ONLY a valid JSON object where the keys are the UI properties and the values are the EXACT matching database keys from the list above.
5876
5915
  If no good match is found for a property, omit it.
5877
5916
 
5878
5917
  Example:
5879
5918
  {
5880
- "name": "Product_Title",
5881
- "price": "MSRP_USD",
5882
- "brand": "VendorName"
5919
+ "name": "Title",
5920
+ "price": "Variant Price",
5921
+ "brand": "Vendor",
5922
+ "image": "Image Src",
5923
+ "stock": "Variant Inventory Qty"
5883
5924
  }
5884
5925
  `;
5885
5926
  try {
@@ -6170,7 +6211,10 @@ var Pipeline = class {
6170
6211
  upsertBatchOptions
6171
6212
  );
6172
6213
  if (upsertResult.errors.length > 0) {
6173
- console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed`);
6214
+ console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed. Error details:`);
6215
+ upsertResult.errors.forEach((err, idx) => {
6216
+ console.warn(` Batch ${idx + 1} Error: ${err.error.message || String(err.error)}`);
6217
+ });
6174
6218
  }
6175
6219
  return upsertResult.totalProcessed;
6176
6220
  }
@@ -6285,8 +6329,9 @@ var Pipeline = class {
6285
6329
  this.embeddingCache.set(cacheKey, queryVector);
6286
6330
  }
6287
6331
  const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_j = this.config.rag) == null ? void 0 : _j.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
6332
+ const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
6288
6333
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
6289
- const wantsExhaustiveList = hasNumericPredicates || /\b(list|all|show|provide|give|get)\b/i.test(question);
6334
+ const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
6290
6335
  const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
6291
6336
  const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
6292
6337
  const retrieveEnd = performance.now();
@@ -6294,15 +6339,28 @@ var Pipeline = class {
6294
6339
  const retrieveMs = retrieveEnd - embedStart;
6295
6340
  const rerankStart = performance.now();
6296
6341
  const structuredSources = this.applyStructuredFilters(rawSources, filter);
6297
- let sources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
6342
+ let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
6343
+ const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
6298
6344
  if (!hasNumericPredicates && ((_k = this.config.rag) == null ? void 0 : _k.useReranking)) {
6299
- sources = yield new __await(this.reranker.rerank(sources, question, topK));
6345
+ fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
6300
6346
  } else if (!wantsExhaustiveList) {
6301
- sources = sources.slice(0, topK);
6347
+ fullSources = fullSources.slice(0, topK);
6302
6348
  }
6303
6349
  const rerankMs = performance.now() - rerankStart;
6304
- let context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
6350
+ let context = fullSources.length ? fullSources.map((m, i) => `[Source ${i + 1}]
6305
6351
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
6352
+ let displayCount = 15;
6353
+ if (hasMetadataFilter) {
6354
+ displayCount = fullSources.length;
6355
+ } else {
6356
+ const baseThreshold = Math.max(scoreThreshold, 0.4);
6357
+ const highlyRelevant = fullSources.filter((m) => m.score >= baseThreshold);
6358
+ displayCount = Math.max(highlyRelevant.length, topK);
6359
+ if (displayCount > 15) {
6360
+ displayCount = 15;
6361
+ }
6362
+ }
6363
+ const sources = [...fullSources].sort((a, b) => b.score - a.score).slice(0, displayCount);
6306
6364
  if (graphData && graphData.nodes.length > 0) {
6307
6365
  const graphContext = graphData.nodes.map(
6308
6366
  (n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
@@ -6315,7 +6373,18 @@ ${context}`;
6315
6373
  }
6316
6374
  const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
6317
6375
  const trainedSchemaPromise = allMetadataKeys.length > 0 ? SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => void 0) : Promise.resolve(void 0);
6318
- const restrictionSuffix = "\n\n(IMPORTANT: Use plain text only. NEVER generate 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 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.)";
6376
+ const uiTransformationPromise = trainedSchemaPromise.then(
6377
+ (trainedSchema) => this.generateUiTransformation(
6378
+ question,
6379
+ sources,
6380
+ trainedSchema,
6381
+ hasNumericPredicates
6382
+ )
6383
+ ).catch((uiError) => {
6384
+ console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
6385
+ return UITransformer.transform(question, sources, this.config);
6386
+ });
6387
+ 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.)";
6319
6388
  const hardenedHistory = [...history];
6320
6389
  const userQuestion = { role: "user", content: question + restrictionSuffix };
6321
6390
  const messages = [...hardenedHistory, userQuestion];
@@ -6385,19 +6454,7 @@ ${context}`;
6385
6454
  tokens,
6386
6455
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
6387
6456
  };
6388
- let uiTransformation;
6389
- try {
6390
- const trainedSchema = yield new __await(trainedSchemaPromise);
6391
- uiTransformation = yield new __await(this.generateUiTransformation(
6392
- question,
6393
- sources,
6394
- trainedSchema,
6395
- hasNumericPredicates
6396
- ));
6397
- } catch (uiError) {
6398
- console.warn("[Pipeline] UI transformation failed before metadata yield:", uiError);
6399
- uiTransformation = UITransformer.transform(question, sources, this.config);
6400
- }
6457
+ const uiTransformation = yield new __await(uiTransformationPromise);
6401
6458
  yield {
6402
6459
  reply: "",
6403
6460
  sources,
@@ -6917,15 +6974,24 @@ function createStreamHandler(configOrPlugin) {
6917
6974
  });
6918
6975
  }
6919
6976
  const encoder = new TextEncoder();
6977
+ let isActive = true;
6920
6978
  const stream = new ReadableStream({
6921
6979
  async start(controller) {
6922
6980
  var _a;
6923
- const enqueue = (text) => controller.enqueue(encoder.encode(text));
6981
+ const enqueue = (text) => {
6982
+ if (!isActive) return;
6983
+ try {
6984
+ controller.enqueue(encoder.encode(text));
6985
+ } catch (err) {
6986
+ console.warn("[createStreamHandler] Failed to enqueue (stream already closed):", err);
6987
+ }
6988
+ };
6924
6989
  try {
6925
6990
  const pipelineStream = plugin.chatStream(message, history, namespace);
6926
6991
  try {
6927
6992
  for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
6928
6993
  const chunk = temp.value;
6994
+ if (!isActive) break;
6929
6995
  if (typeof chunk === "string") {
6930
6996
  enqueue(sseTextFrame(chunk));
6931
6997
  } else {
@@ -6963,12 +7029,27 @@ function createStreamHandler(configOrPlugin) {
6963
7029
  }
6964
7030
  }
6965
7031
  } catch (streamError) {
6966
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
6967
- console.error("[createStreamHandler] Stream error:", streamError);
6968
- enqueue(sseErrorFrame(errorMessage));
7032
+ if (isActive) {
7033
+ const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
7034
+ console.error("[createStreamHandler] Stream error:", streamError);
7035
+ try {
7036
+ enqueue(sseErrorFrame(errorMessage));
7037
+ } catch (e) {
7038
+ }
7039
+ }
6969
7040
  } finally {
6970
- controller.close();
7041
+ if (isActive) {
7042
+ isActive = false;
7043
+ try {
7044
+ controller.close();
7045
+ } catch (e) {
7046
+ }
7047
+ }
6971
7048
  }
7049
+ },
7050
+ cancel(reason) {
7051
+ isActive = false;
7052
+ console.log("[createStreamHandler] Stream connection closed by client:", reason);
6972
7053
  }
6973
7054
  });
6974
7055
  return new Response(stream, { headers: SSE_HEADERS });
@@ -7029,6 +7110,7 @@ function createUploadHandler(configOrPlugin) {
7029
7110
  if (parsed.data && parsed.data.length > 0) {
7030
7111
  let i = 0;
7031
7112
  let lastRowData = null;
7113
+ const csvCols = Object.keys(parsed.data[0]);
7032
7114
  for (const row of parsed.data) {
7033
7115
  i++;
7034
7116
  const rowData = row;
@@ -7050,12 +7132,14 @@ function createUploadHandler(configOrPlugin) {
7050
7132
  documents.push({
7051
7133
  docId: `${file.name}-row-${i}`,
7052
7134
  content: contentParts.join(", "),
7053
- metadata: __spreadValues(__spreadValues({
7135
+ metadata: __spreadValues(__spreadProps(__spreadValues({
7054
7136
  fileName: file.name,
7055
7137
  fileSize: file.size,
7056
7138
  fileType: file.type,
7057
7139
  uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
7058
- }, dimension ? { dimension } : {}), rowData)
7140
+ }, dimension ? { dimension } : {}), {
7141
+ csvHeaders: csvCols
7142
+ }), rowData)
7059
7143
  });
7060
7144
  }
7061
7145
  }
@@ -1,4 +1,4 @@
1
- import { k as RagConfig, I as ILLMProvider, C as ChatMessage, d as ChatResponse, g as IngestDocument } from './ILLMProvider-BQyKZLnd.mjs';
1
+ import { k as RagConfig, I as ILLMProvider, C as ChatMessage, d as ChatResponse, g as IngestDocument } from './ILLMProvider-Bw2A28nU.mjs';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  interface ValidationError {
@@ -1,4 +1,4 @@
1
- import { k as RagConfig, I as ILLMProvider, C as ChatMessage, d as ChatResponse, g as IngestDocument } from './ILLMProvider-BQyKZLnd.js';
1
+ import { k as RagConfig, I as ILLMProvider, C as ChatMessage, d as ChatResponse, g as IngestDocument } from './ILLMProvider-Bw2A28nU.js';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  interface ValidationError {
package/dist/index.css CHANGED
@@ -313,6 +313,9 @@
313
313
  .right-0 {
314
314
  right: calc(var(--spacing) * 0);
315
315
  }
316
+ .right-2 {
317
+ right: calc(var(--spacing) * 2);
318
+ }
316
319
  .right-4 {
317
320
  right: calc(var(--spacing) * 4);
318
321
  }
@@ -809,6 +812,12 @@
809
812
  --tw-scale-z: 90%;
810
813
  scale: var(--tw-scale-x) var(--tw-scale-y);
811
814
  }
815
+ .scale-95 {
816
+ --tw-scale-x: 95%;
817
+ --tw-scale-y: 95%;
818
+ --tw-scale-z: 95%;
819
+ scale: var(--tw-scale-x) var(--tw-scale-y);
820
+ }
812
821
  .scale-100 {
813
822
  --tw-scale-x: 100%;
814
823
  --tw-scale-y: 100%;
@@ -1058,6 +1067,9 @@
1058
1067
  .rounded-3xl {
1059
1068
  border-radius: var(--radius-3xl);
1060
1069
  }
1070
+ .rounded-\[2px\] {
1071
+ border-radius: 2px;
1072
+ }
1061
1073
  .rounded-full {
1062
1074
  border-radius: calc(infinity * 1px);
1063
1075
  }
@@ -1144,6 +1156,12 @@
1144
1156
  .border-emerald-500 {
1145
1157
  border-color: var(--color-emerald-500);
1146
1158
  }
1159
+ .border-emerald-500\/20 {
1160
+ border-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 20%, transparent);
1161
+ @supports (color: color-mix(in lab, red, red)) {
1162
+ border-color: color-mix(in oklab, var(--color-emerald-500) 20%, transparent);
1163
+ }
1164
+ }
1147
1165
  .border-indigo-100 {
1148
1166
  border-color: var(--color-indigo-100);
1149
1167
  }
@@ -1219,6 +1237,12 @@
1219
1237
  .bg-emerald-500 {
1220
1238
  background-color: var(--color-emerald-500);
1221
1239
  }
1240
+ .bg-emerald-500\/10 {
1241
+ background-color: color-mix(in srgb, oklch(69.6% 0.17 162.48) 10%, transparent);
1242
+ @supports (color: color-mix(in lab, red, red)) {
1243
+ background-color: color-mix(in oklab, var(--color-emerald-500) 10%, transparent);
1244
+ }
1245
+ }
1222
1246
  .bg-green-500 {
1223
1247
  background-color: var(--color-green-500);
1224
1248
  }
@@ -1261,6 +1285,12 @@
1261
1285
  .bg-slate-400 {
1262
1286
  background-color: var(--color-slate-400);
1263
1287
  }
1288
+ .bg-slate-500\/5 {
1289
+ background-color: color-mix(in srgb, oklch(55.4% 0.046 257.417) 5%, transparent);
1290
+ @supports (color: color-mix(in lab, red, red)) {
1291
+ background-color: color-mix(in oklab, var(--color-slate-500) 5%, transparent);
1292
+ }
1293
+ }
1264
1294
  .bg-slate-900 {
1265
1295
  background-color: var(--color-slate-900);
1266
1296
  }
@@ -1794,6 +1824,16 @@
1794
1824
  .\[animation-delay\:300ms\] {
1795
1825
  animation-delay: 300ms;
1796
1826
  }
1827
+ .group-hover\:scale-100 {
1828
+ &:is(:where(.group):hover *) {
1829
+ @media (hover: hover) {
1830
+ --tw-scale-x: 100%;
1831
+ --tw-scale-y: 100%;
1832
+ --tw-scale-z: 100%;
1833
+ scale: var(--tw-scale-x) var(--tw-scale-y);
1834
+ }
1835
+ }
1836
+ }
1797
1837
  .group-hover\:scale-105 {
1798
1838
  &:is(:where(.group):hover *) {
1799
1839
  @media (hover: hover) {
@@ -1933,6 +1973,13 @@
1933
1973
  }
1934
1974
  }
1935
1975
  }
1976
+ .hover\:bg-rose-600 {
1977
+ &:hover {
1978
+ @media (hover: hover) {
1979
+ background-color: var(--color-rose-600);
1980
+ }
1981
+ }
1982
+ }
1936
1983
  .hover\:bg-slate-50 {
1937
1984
  &:hover {
1938
1985
  @media (hover: hover) {
@@ -1974,6 +2021,16 @@
1974
2021
  }
1975
2022
  }
1976
2023
  }
2024
+ .hover\:bg-slate-500\/10 {
2025
+ &:hover {
2026
+ @media (hover: hover) {
2027
+ background-color: color-mix(in srgb, oklch(55.4% 0.046 257.417) 10%, transparent);
2028
+ @supports (color: color-mix(in lab, red, red)) {
2029
+ background-color: color-mix(in oklab, var(--color-slate-500) 10%, transparent);
2030
+ }
2031
+ }
2032
+ }
2033
+ }
1977
2034
  .hover\:bg-white {
1978
2035
  &:hover {
1979
2036
  @media (hover: hover) {
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, MouseEvent, ReactNode } from 'react';
3
- import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-BQyKZLnd.mjs';
4
- export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-BQyKZLnd.mjs';
3
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-Bw2A28nU.mjs';
4
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-Bw2A28nU.mjs';
5
5
  export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.mjs';
6
6
 
7
7
  type ChatViewportSize = 'compact' | 'medium' | 'large';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { CSSProperties, MouseEvent, ReactNode } from 'react';
3
- import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-BQyKZLnd.js';
4
- export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-BQyKZLnd.js';
3
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, O as ObservabilityTrace, a as UseRagChatOptions, b as UseRagChatReturn } from './ILLMProvider-Bw2A28nU.js';
4
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbedOptions, e as EmbeddingConfig, f as EmbeddingProvider, I as ILLMProvider, g as IngestDocument, L as LLMConfig, h as LLMProvider, i as LatencyBreakdown, j as RAGConfig, k as RagConfig, l as RetrievedChunk, T as TokenUsage, m as UpsertDocument, n as VectorDBConfig, o as VectorDBProvider } from './ILLMProvider-Bw2A28nU.js';
5
5
  export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.js';
6
6
 
7
7
  type ChatViewportSize = 'compact' | 'medium' | 'large';