@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.
@@ -52,6 +52,8 @@ interface UseRagChatReturn {
52
52
  retry: () => Promise<void>;
53
53
  /** Programmatically set the conversation (e.g. to restore from a DB) */
54
54
  setMessages: React.Dispatch<React.SetStateAction<RagMessage[]>>;
55
+ /** Abort the current active stream request */
56
+ stop: () => void;
55
57
  }
56
58
 
57
59
  /**
@@ -52,6 +52,8 @@ interface UseRagChatReturn {
52
52
  retry: () => Promise<void>;
53
53
  /** Programmatically set the conversation (e.g. to restore from a DB) */
54
54
  setMessages: React.Dispatch<React.SetStateAction<RagMessage[]>>;
55
+ /** Abort the current active stream request */
56
+ stop: () => void;
55
57
  }
56
58
 
57
59
  /**
@@ -1,3 +1,3 @@
1
- import '../ILLMProvider-BQyKZLnd.mjs';
2
- export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, k as createSuggestionsHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, l as sseObservabilityFrame, j as sseTextFrame, m as sseUIFrame } from '../index-CDftK3qs.mjs';
1
+ import '../ILLMProvider-Bw2A28nU.mjs';
2
+ export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, k as createSuggestionsHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, l as sseObservabilityFrame, j as sseTextFrame, m as sseUIFrame } from '../index-B70ZLkfG.mjs';
3
3
  import 'next/server';
@@ -1,3 +1,3 @@
1
- import '../ILLMProvider-BQyKZLnd.js';
2
- export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, k as createSuggestionsHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, l as sseObservabilityFrame, j as sseTextFrame, m as sseUIFrame } from '../index-A0GqPsaG.js';
1
+ import '../ILLMProvider-Bw2A28nU.js';
2
+ export { c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, k as createSuggestionsHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, l as sseObservabilityFrame, j as sseTextFrame, m as sseUIFrame } from '../index-DVu-mkAM.js';
3
3
  import 'next/server';
@@ -540,6 +540,82 @@ var init_PostgreSQLProvider = __esm({
540
540
  }
541
541
  });
542
542
 
543
+ // src/utils/synonyms.ts
544
+ function resolveMetadataValue(meta, uiKey) {
545
+ var _a;
546
+ const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
547
+ const keys = Object.keys(meta);
548
+ const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
549
+ let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
550
+ if (match !== void 0) return meta[match];
551
+ match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
552
+ if (match !== void 0) return meta[match];
553
+ const isBlacklisted = (kl) => {
554
+ return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
555
+ };
556
+ match = keys.find((k) => {
557
+ const kl = k.toLowerCase();
558
+ if (isBlacklisted(kl)) return false;
559
+ return kl.includes(uiKey.toLowerCase());
560
+ });
561
+ if (match !== void 0) return meta[match];
562
+ match = keys.find((k) => {
563
+ const kl = k.toLowerCase();
564
+ if (isBlacklisted(kl)) return false;
565
+ return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
566
+ });
567
+ return match !== void 0 ? meta[match] : void 0;
568
+ }
569
+ var FIELD_SYNONYMS;
570
+ var init_synonyms = __esm({
571
+ "src/utils/synonyms.ts"() {
572
+ "use strict";
573
+ FIELD_SYNONYMS = {
574
+ name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
575
+ price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd", "variant price"],
576
+ brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
577
+ image: [
578
+ "imageUrl",
579
+ "thumbnail",
580
+ "img",
581
+ "url",
582
+ "photo",
583
+ "picture",
584
+ "media",
585
+ "image_url",
586
+ "main_image",
587
+ "product_image",
588
+ "thumb",
589
+ "image src",
590
+ "variant image"
591
+ ],
592
+ stock: [
593
+ "inventory",
594
+ "quantity",
595
+ "count",
596
+ "availability",
597
+ "stock_level",
598
+ "inStock",
599
+ "is_available",
600
+ "in stock",
601
+ "status",
602
+ "variant inventory qty"
603
+ ],
604
+ category: [
605
+ "product_category",
606
+ "product category",
607
+ "category_name",
608
+ "category name",
609
+ "department",
610
+ "collection",
611
+ "type"
612
+ ],
613
+ description: ["summary", "content", "body", "text", "info", "details", "body (html)", "seo description"],
614
+ link: ["url", "href", "product_url", "page_url", "link"]
615
+ };
616
+ }
617
+ });
618
+
543
619
  // src/providers/vectordb/MultiTablePostgresProvider.ts
544
620
  var MultiTablePostgresProvider_exports = {};
545
621
  __export(MultiTablePostgresProvider_exports, {
@@ -551,6 +627,7 @@ var init_MultiTablePostgresProvider = __esm({
551
627
  "use strict";
552
628
  import_pg2 = require("pg");
553
629
  init_BaseVectorProvider();
630
+ init_synonyms();
554
631
  MultiTablePostgresProvider = class extends BaseVectorProvider {
555
632
  constructor(config) {
556
633
  var _a, _b, _c;
@@ -631,8 +708,13 @@ var init_MultiTablePostgresProvider = __esm({
631
708
  }
632
709
  tableName = tableName.replace(/[^a-z0-9_]/gi, "_").toLowerCase() || this.uploadTable;
633
710
  const firstMeta = fileDocs[0].metadata || {};
634
- const systemKeys = ["fileName", "fileSize", "fileType", "uploadedAt", "dimension", "chunkIndex", "id", "namespace", "content", "metadata", "embedding"];
635
- const csvHeaders = Object.keys(firstMeta).filter((k) => !systemKeys.includes(k) && !systemKeys.includes(k.toLowerCase()));
711
+ let csvHeaders = [];
712
+ if (Array.isArray(firstMeta.csvHeaders)) {
713
+ csvHeaders = firstMeta.csvHeaders;
714
+ } else {
715
+ const systemKeys = ["fileName", "fileSize", "fileType", "uploadedAt", "dimension", "chunkIndex", "id", "namespace", "content", "metadata", "embedding", "docId", "docid", "chunkId", "chunkid", "csvHeaders", "csvheaders"];
716
+ csvHeaders = Object.keys(firstMeta).filter((k) => !systemKeys.includes(k) && !systemKeys.includes(k.toLowerCase()));
717
+ }
636
718
  const columnDefs = csvHeaders.map((h) => `"${h}" TEXT`).join(",\n ");
637
719
  const createTableSql = `
638
720
  CREATE TABLE IF NOT EXISTS "${tableName}" (
@@ -725,10 +807,26 @@ var init_MultiTablePostgresProvider = __esm({
725
807
  };
726
808
  const dynamicKeywordQuery = getDynamicKeywordQuery();
727
809
  const tableLimit = Math.max(topK, 50);
810
+ const metadataFilters = _filter == null ? void 0 : _filter.metadata;
728
811
  const queryPromises = this.tables.map(async (table) => {
729
812
  try {
730
813
  let sqlQuery = "";
731
814
  let params = [];
815
+ let whereClause = "";
816
+ const filterParams = [];
817
+ if (metadataFilters && Object.keys(metadataFilters).length > 0) {
818
+ const conditions = Object.entries(metadataFilters).map(([key, val]) => {
819
+ var _a3;
820
+ filterParams.push(String(val));
821
+ const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
822
+ const paramIdx = baseOffset + filterParams.length;
823
+ const synonyms = (_a3 = FIELD_SYNONYMS[key]) != null ? _a3 : [];
824
+ const keysToCheck = [key, ...synonyms];
825
+ const coalesceExprs = keysToCheck.map((k) => `LOWER(metadata->>'${k}')`);
826
+ return `COALESCE(${coalesceExprs.join(", ")}) = LOWER($${paramIdx})`;
827
+ });
828
+ whereClause = `WHERE ${conditions.join(" AND ")}`;
829
+ }
732
830
  if (queryText && dynamicKeywordQuery) {
733
831
  const hasEntityHints = entityHints.length > 0;
734
832
  const exactNameScoreExpr = hasEntityHints ? `+ (
@@ -745,19 +843,21 @@ var init_MultiTablePostgresProvider = __esm({
745
843
  COALESCE(ts_rank(to_tsvector('english', (to_jsonb(t) - 'embedding')::text), to_tsquery('english', $2)), 0) AS keyword_score,
746
844
  ((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
747
845
  FROM "${table}" t
846
+ ${whereClause}
748
847
  ORDER BY hybrid_score DESC
749
848
  LIMIT ${tableLimit}
750
849
  `;
751
- params = [vectorLiteral, dynamicKeywordQuery];
850
+ params = [vectorLiteral, dynamicKeywordQuery, ...filterParams];
752
851
  } else {
753
852
  sqlQuery = `
754
853
  SELECT *,
755
854
  (1 - (embedding <=> $1::vector)) AS hybrid_score
756
855
  FROM "${table}" t
856
+ ${whereClause}
757
857
  ORDER BY hybrid_score DESC
758
858
  LIMIT ${tableLimit}
759
859
  `;
760
- params = [vectorLiteral];
860
+ params = [vectorLiteral, ...filterParams];
761
861
  }
762
862
  const result = await this.pool.query(sqlQuery, params);
763
863
  if (result.rowCount && result.rowCount > 0) {
@@ -990,12 +1090,15 @@ var init_MongoDBProvider = __esm({
990
1090
  }
991
1091
  );
992
1092
  const results = await this.collection.aggregate(pipeline).toArray();
993
- return results.map((res) => ({
994
- id: res._id,
995
- content: res[this.contentKey],
996
- metadata: res[this.metadataKey] || {},
997
- score: res.score
998
- }));
1093
+ return results.map((res) => {
1094
+ const normalizedScore = res.score * 2 - 1;
1095
+ return {
1096
+ id: res._id,
1097
+ content: res[this.contentKey],
1098
+ metadata: res[this.metadataKey] || {},
1099
+ score: normalizedScore
1100
+ };
1101
+ });
999
1102
  }
1000
1103
  async delete(id, namespace) {
1001
1104
  await this.collection.deleteOne(__spreadValues({ _id: id }, namespace ? { namespace } : {}));
@@ -4353,7 +4456,8 @@ var QueryProcessor = class {
4353
4456
  const fieldValuePatterns = [
4354
4457
  new RegExp(`\\b${fieldPattern}\\s*(?:=|:)\\s*["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4355
4458
  new RegExp(`\\b${fieldPattern}\\s+(?:is|are|was|were|equals?|equal to|named|called)\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4356
- new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
4459
+ new RegExp(`\\bwith\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi"),
4460
+ new RegExp(`\\b(?:under|in|for|from|of)\\s+${fieldPattern}\\s+["']?${valuePattern}["']?(?=[?.!,]|$)`, "gi")
4357
4461
  ];
4358
4462
  for (const pattern of fieldValuePatterns) {
4359
4463
  for (const match of question.matchAll(pattern)) {
@@ -4587,73 +4691,8 @@ var LLMRouter = class {
4587
4691
  }
4588
4692
  };
4589
4693
 
4590
- // src/utils/synonyms.ts
4591
- var FIELD_SYNONYMS = {
4592
- name: ["product", "item", "title", "label", "heading", "subject", "product name", "item name"],
4593
- price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
4594
- brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
4595
- image: [
4596
- "imageUrl",
4597
- "thumbnail",
4598
- "img",
4599
- "url",
4600
- "photo",
4601
- "picture",
4602
- "media",
4603
- "image_url",
4604
- "main_image",
4605
- "product_image",
4606
- "thumb"
4607
- ],
4608
- stock: [
4609
- "inventory",
4610
- "quantity",
4611
- "count",
4612
- "availability",
4613
- "stock_level",
4614
- "inStock",
4615
- "is_available",
4616
- "in stock",
4617
- "status"
4618
- ],
4619
- category: [
4620
- "product_category",
4621
- "product category",
4622
- "category_name",
4623
- "category name",
4624
- "department",
4625
- "collection"
4626
- ],
4627
- description: ["summary", "content", "body", "text", "info", "details"],
4628
- link: ["url", "href", "product_url", "page_url", "link"]
4629
- };
4630
- function resolveMetadataValue(meta, uiKey) {
4631
- var _a;
4632
- const synonyms = (_a = FIELD_SYNONYMS[uiKey]) != null ? _a : [];
4633
- const keys = Object.keys(meta);
4634
- const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
4635
- let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
4636
- if (match !== void 0) return meta[match];
4637
- match = keys.find((k) => synonyms.map((s) => s.toLowerCase()).includes(k.toLowerCase()));
4638
- if (match !== void 0) return meta[match];
4639
- const isBlacklisted = (kl) => {
4640
- return systemKeys.includes(kl) || kl.startsWith("option1") || kl.startsWith("option2") || kl.startsWith("option3");
4641
- };
4642
- match = keys.find((k) => {
4643
- const kl = k.toLowerCase();
4644
- if (isBlacklisted(kl)) return false;
4645
- return kl.includes(uiKey.toLowerCase());
4646
- });
4647
- if (match !== void 0) return meta[match];
4648
- match = keys.find((k) => {
4649
- const kl = k.toLowerCase();
4650
- if (isBlacklisted(kl)) return false;
4651
- return synonyms.some((sk) => kl.includes(sk.toLowerCase()) || sk.toLowerCase().includes(kl));
4652
- });
4653
- return match !== void 0 ? meta[match] : void 0;
4654
- }
4655
-
4656
4694
  // src/utils/UITransformer.ts
4695
+ init_synonyms();
4657
4696
  var UITransformer = class {
4658
4697
  // ─── Public Entry Points ─────────────────────────────────────────────────
4659
4698
  /**
@@ -4950,7 +4989,7 @@ RULES:
4950
4989
  }
4951
4990
  // ─── Transform Helpers ────────────────────────────────────────────────────
4952
4991
  static transformToProductCarousel(data, config, trainedSchema) {
4953
- const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null);
4992
+ const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null).slice(0, 15);
4954
4993
  return {
4955
4994
  type: "product_carousel",
4956
4995
  title: "Recommended Products",
@@ -5909,14 +5948,16 @@ Given these metadata keys from a database: [${keys.join(", ")}]
5909
5948
  Identify which keys best correspond to these standard UI properties:
5910
5949
  ${propertyList}
5911
5950
 
5912
- Return ONLY a JSON object where the keys are the UI properties and the values are the matching database keys.
5951
+ 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.
5913
5952
  If no good match is found for a property, omit it.
5914
5953
 
5915
5954
  Example:
5916
5955
  {
5917
- "name": "Product_Title",
5918
- "price": "MSRP_USD",
5919
- "brand": "VendorName"
5956
+ "name": "Title",
5957
+ "price": "Variant Price",
5958
+ "brand": "Vendor",
5959
+ "image": "Image Src",
5960
+ "stock": "Variant Inventory Qty"
5920
5961
  }
5921
5962
  `;
5922
5963
  try {
@@ -6207,7 +6248,10 @@ var Pipeline = class {
6207
6248
  upsertBatchOptions
6208
6249
  );
6209
6250
  if (upsertResult.errors.length > 0) {
6210
- console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed`);
6251
+ console.warn(`[Pipeline] Ingestion: ${upsertResult.errors.length} batches failed. Error details:`);
6252
+ upsertResult.errors.forEach((err, idx) => {
6253
+ console.warn(` Batch ${idx + 1} Error: ${err.error.message || String(err.error)}`);
6254
+ });
6211
6255
  }
6212
6256
  return upsertResult.totalProcessed;
6213
6257
  }
@@ -6322,8 +6366,9 @@ var Pipeline = class {
6322
6366
  this.embeddingCache.set(cacheKey, queryVector);
6323
6367
  }
6324
6368
  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;
6369
+ const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
6325
6370
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
6326
- const wantsExhaustiveList = hasNumericPredicates || /\b(list|all|show|provide|give|get)\b/i.test(question);
6371
+ const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
6327
6372
  const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
6328
6373
  const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
6329
6374
  const retrieveEnd = performance.now();
@@ -6331,15 +6376,28 @@ var Pipeline = class {
6331
6376
  const retrieveMs = retrieveEnd - embedStart;
6332
6377
  const rerankStart = performance.now();
6333
6378
  const structuredSources = this.applyStructuredFilters(rawSources, filter);
6334
- let sources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
6379
+ let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
6380
+ const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
6335
6381
  if (!hasNumericPredicates && ((_k = this.config.rag) == null ? void 0 : _k.useReranking)) {
6336
- sources = yield new __await(this.reranker.rerank(sources, question, topK));
6382
+ fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
6337
6383
  } else if (!wantsExhaustiveList) {
6338
- sources = sources.slice(0, topK);
6384
+ fullSources = fullSources.slice(0, topK);
6339
6385
  }
6340
6386
  const rerankMs = performance.now() - rerankStart;
6341
- let context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
6387
+ let context = fullSources.length ? fullSources.map((m, i) => `[Source ${i + 1}]
6342
6388
  ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
6389
+ let displayCount = 15;
6390
+ if (hasMetadataFilter) {
6391
+ displayCount = fullSources.length;
6392
+ } else {
6393
+ const baseThreshold = Math.max(scoreThreshold, 0.4);
6394
+ const highlyRelevant = fullSources.filter((m) => m.score >= baseThreshold);
6395
+ displayCount = Math.max(highlyRelevant.length, topK);
6396
+ if (displayCount > 15) {
6397
+ displayCount = 15;
6398
+ }
6399
+ }
6400
+ const sources = [...fullSources].sort((a, b) => b.score - a.score).slice(0, displayCount);
6343
6401
  if (graphData && graphData.nodes.length > 0) {
6344
6402
  const graphContext = graphData.nodes.map(
6345
6403
  (n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
@@ -6352,7 +6410,18 @@ ${context}`;
6352
6410
  }
6353
6411
  const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
6354
6412
  const trainedSchemaPromise = allMetadataKeys.length > 0 ? SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => void 0) : Promise.resolve(void 0);
6355
- 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.)";
6413
+ const uiTransformationPromise = trainedSchemaPromise.then(
6414
+ (trainedSchema) => this.generateUiTransformation(
6415
+ question,
6416
+ sources,
6417
+ trainedSchema,
6418
+ hasNumericPredicates
6419
+ )
6420
+ ).catch((uiError) => {
6421
+ console.warn("[Pipeline] UI transformation failed concurrently:", uiError);
6422
+ return UITransformer.transform(question, sources, this.config);
6423
+ });
6424
+ 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.)";
6356
6425
  const hardenedHistory = [...history];
6357
6426
  const userQuestion = { role: "user", content: question + restrictionSuffix };
6358
6427
  const messages = [...hardenedHistory, userQuestion];
@@ -6422,19 +6491,7 @@ ${context}`;
6422
6491
  tokens,
6423
6492
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
6424
6493
  };
6425
- let uiTransformation;
6426
- try {
6427
- const trainedSchema = yield new __await(trainedSchemaPromise);
6428
- uiTransformation = yield new __await(this.generateUiTransformation(
6429
- question,
6430
- sources,
6431
- trainedSchema,
6432
- hasNumericPredicates
6433
- ));
6434
- } catch (uiError) {
6435
- console.warn("[Pipeline] UI transformation failed before metadata yield:", uiError);
6436
- uiTransformation = UITransformer.transform(question, sources, this.config);
6437
- }
6494
+ const uiTransformation = yield new __await(uiTransformationPromise);
6438
6495
  yield {
6439
6496
  reply: "",
6440
6497
  sources,
@@ -6954,15 +7011,24 @@ function createStreamHandler(configOrPlugin) {
6954
7011
  });
6955
7012
  }
6956
7013
  const encoder = new TextEncoder();
7014
+ let isActive = true;
6957
7015
  const stream = new ReadableStream({
6958
7016
  async start(controller) {
6959
7017
  var _a;
6960
- const enqueue = (text) => controller.enqueue(encoder.encode(text));
7018
+ const enqueue = (text) => {
7019
+ if (!isActive) return;
7020
+ try {
7021
+ controller.enqueue(encoder.encode(text));
7022
+ } catch (err) {
7023
+ console.warn("[createStreamHandler] Failed to enqueue (stream already closed):", err);
7024
+ }
7025
+ };
6961
7026
  try {
6962
7027
  const pipelineStream = plugin.chatStream(message, history, namespace);
6963
7028
  try {
6964
7029
  for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
6965
7030
  const chunk = temp.value;
7031
+ if (!isActive) break;
6966
7032
  if (typeof chunk === "string") {
6967
7033
  enqueue(sseTextFrame(chunk));
6968
7034
  } else {
@@ -7000,12 +7066,27 @@ function createStreamHandler(configOrPlugin) {
7000
7066
  }
7001
7067
  }
7002
7068
  } catch (streamError) {
7003
- const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
7004
- console.error("[createStreamHandler] Stream error:", streamError);
7005
- enqueue(sseErrorFrame(errorMessage));
7069
+ if (isActive) {
7070
+ const errorMessage = streamError instanceof Error ? streamError.message : String(streamError);
7071
+ console.error("[createStreamHandler] Stream error:", streamError);
7072
+ try {
7073
+ enqueue(sseErrorFrame(errorMessage));
7074
+ } catch (e) {
7075
+ }
7076
+ }
7006
7077
  } finally {
7007
- controller.close();
7078
+ if (isActive) {
7079
+ isActive = false;
7080
+ try {
7081
+ controller.close();
7082
+ } catch (e) {
7083
+ }
7084
+ }
7008
7085
  }
7086
+ },
7087
+ cancel(reason) {
7088
+ isActive = false;
7089
+ console.log("[createStreamHandler] Stream connection closed by client:", reason);
7009
7090
  }
7010
7091
  });
7011
7092
  return new Response(stream, { headers: SSE_HEADERS });
@@ -7066,6 +7147,7 @@ function createUploadHandler(configOrPlugin) {
7066
7147
  if (parsed.data && parsed.data.length > 0) {
7067
7148
  let i = 0;
7068
7149
  let lastRowData = null;
7150
+ const csvCols = Object.keys(parsed.data[0]);
7069
7151
  for (const row of parsed.data) {
7070
7152
  i++;
7071
7153
  const rowData = row;
@@ -7087,12 +7169,14 @@ function createUploadHandler(configOrPlugin) {
7087
7169
  documents.push({
7088
7170
  docId: `${file.name}-row-${i}`,
7089
7171
  content: contentParts.join(", "),
7090
- metadata: __spreadValues(__spreadValues({
7172
+ metadata: __spreadValues(__spreadProps(__spreadValues({
7091
7173
  fileName: file.name,
7092
7174
  fileSize: file.size,
7093
7175
  fileType: file.type,
7094
7176
  uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
7095
- }, dimension ? { dimension } : {}), rowData)
7177
+ }, dimension ? { dimension } : {}), {
7178
+ csvHeaders: csvCols
7179
+ }), rowData)
7096
7180
  });
7097
7181
  }
7098
7182
  }