@retrivora-ai/rag-engine 2.0.6 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.mjs CHANGED
@@ -3938,9 +3938,9 @@ ${context != null ? context : "None"}` },
3938
3938
  }
3939
3939
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
3940
3940
  if (isSelfHost || Boolean(process.env.VERCEL)) {
3941
- try {
3942
- const _g2 = globalThis;
3943
- if (typeof _g2.__retrivoraDispatchChat === "function") {
3941
+ const _g2 = globalThis;
3942
+ if (typeof _g2.__retrivoraDispatchChat === "function") {
3943
+ try {
3944
3944
  const res = await _g2.__retrivoraDispatchChat({
3945
3945
  model: this.model,
3946
3946
  messages: formattedMessages,
@@ -3950,8 +3950,9 @@ ${context != null ? context : "None"}` },
3950
3950
  if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
3951
3951
  return res.response.choices[0].message.content;
3952
3952
  }
3953
+ } catch (dispatchErr) {
3954
+ throw dispatchErr;
3953
3955
  }
3954
- } catch (e) {
3955
3956
  }
3956
3957
  }
3957
3958
  const { data } = await this.http.post(path2, payload);
@@ -4003,9 +4004,9 @@ ${context != null ? context : "None"}` },
4003
4004
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4004
4005
  let streamBody = null;
4005
4006
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4006
- try {
4007
- const _g3 = globalThis;
4008
- if (typeof _g3.__retrivoraDispatchChat === "function") {
4007
+ const _g3 = globalThis;
4008
+ if (typeof _g3.__retrivoraDispatchChat === "function") {
4009
+ try {
4009
4010
  const res = yield new __await(_g3.__retrivoraDispatchChat({
4010
4011
  model: this.model,
4011
4012
  messages: formattedMessages,
@@ -4019,8 +4020,9 @@ ${context != null ? context : "None"}` },
4019
4020
  yield res.response.choices[0].message.content;
4020
4021
  return;
4021
4022
  }
4023
+ } catch (dispatchErr) {
4024
+ throw dispatchErr;
4022
4025
  }
4023
- } catch (e) {
4024
4026
  }
4025
4027
  }
4026
4028
  if (!streamBody) {
@@ -4091,9 +4093,9 @@ ${context != null ? context : "None"}` },
4091
4093
  }
4092
4094
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4093
4095
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4094
- try {
4095
- const _g2 = globalThis;
4096
- if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
4096
+ const _g2 = globalThis;
4097
+ if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
4098
+ try {
4097
4099
  const res = await _g2.__retrivoraDispatchEmbedding({
4098
4100
  model: this.model,
4099
4101
  input: text
@@ -4101,8 +4103,9 @@ ${context != null ? context : "None"}` },
4101
4103
  if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
4102
4104
  return res.data[0].embedding;
4103
4105
  }
4106
+ } catch (dispatchErr) {
4107
+ throw dispatchErr;
4104
4108
  }
4105
- } catch (e) {
4106
4109
  }
4107
4110
  }
4108
4111
  const { data } = await this.http.post(path2, payload);
@@ -4695,7 +4698,8 @@ var Reranker = class {
4695
4698
  return matches.sort((a, b) => b.score - a.score).slice(0, limit);
4696
4699
  }
4697
4700
  const scoredMatches = matches.map((match) => {
4698
- const contentLower = match.content.toLowerCase();
4701
+ var _a2;
4702
+ const contentLower = ((_a2 = match == null ? void 0 : match.content) != null ? _a2 : "").toLowerCase();
4699
4703
  let keywordScore = 0;
4700
4704
  keywords.forEach((keyword) => {
4701
4705
  if (contentLower.includes(keyword)) {
@@ -4716,7 +4720,10 @@ var Reranker = class {
4716
4720
  [{ role: "user", content: `Query: "${query}"
4717
4721
 
4718
4722
  Documents:
4719
- ${topN.map((m, i) => `[${i}] ${m.content.replace(/\n/g, " ")}`).join("\n")}` }],
4723
+ ${topN.map((m, i) => {
4724
+ var _a2;
4725
+ return `[${i}] ${((_a2 = m == null ? void 0 : m.content) != null ? _a2 : "").replace(/\n/g, " ")}`;
4726
+ }).join("\n")}` }],
4720
4727
  "",
4721
4728
  {
4722
4729
  systemPrompt: 'You are a relevance ranking expert. Given the user query and a list of retrieved document chunks, rank the chunks by relevance to the query. Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant. Use the indices provided in brackets like [0], [1], etc. Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.',
@@ -5887,10 +5894,10 @@ Return ONLY 'vector', 'graph', or 'both'. No explanation.`;
5887
5894
  "",
5888
5895
  { temperature: 0, maxTokens: 10 }
5889
5896
  );
5890
- const cleanResponse = response.trim().toLowerCase();
5891
- if (cleanResponse.includes("vector")) return "vector";
5892
- if (cleanResponse.includes("graph")) return "graph";
5897
+ const cleanResponse = (response != null ? response : "").trim().toLowerCase();
5893
5898
  if (cleanResponse.includes("both")) return "both";
5899
+ if (cleanResponse.includes("graph")) return "graph";
5900
+ if (cleanResponse.includes("vector")) return "vector";
5894
5901
  } catch (error) {
5895
5902
  console.warn("[QueryProcessor] LLM strategy classification failed, falling back to keywords:", error);
5896
5903
  }
@@ -6064,7 +6071,10 @@ var IntentClassifier = class {
6064
6071
  hasCategoricalFields = catKeys.size > 0;
6065
6072
  numericFieldCount = numericKeys.size;
6066
6073
  categoricalFieldCount = catKeys.size;
6067
- if (productKeyMatches >= 2 || docs.some((d) => d.content.toLowerCase().includes("price") || d.content.toLowerCase().includes("brand"))) {
6074
+ if (productKeyMatches >= 2 || docs.some((d) => {
6075
+ var _a2, _b;
6076
+ return ((_a2 = d == null ? void 0 : d.content) != null ? _a2 : "").toLowerCase().includes("price") || ((_b = d == null ? void 0 : d.content) != null ? _b : "").toLowerCase().includes("brand");
6077
+ })) {
6068
6078
  isProductLike = true;
6069
6079
  }
6070
6080
  }
@@ -6344,7 +6354,10 @@ var TextRendererStrategy = class {
6344
6354
  return { type: "text", title, data: { content: data } };
6345
6355
  }
6346
6356
  const docs = Array.isArray(data) ? data : [];
6347
- const text = docs.map((d) => d.content).join("\n\n");
6357
+ const text = docs.map((d) => {
6358
+ var _a2;
6359
+ return (_a2 = d == null ? void 0 : d.content) != null ? _a2 : "";
6360
+ }).join("\n\n");
6348
6361
  return { type: "text", title, data: { content: text || "No detailed content available." } };
6349
6362
  }
6350
6363
  };
@@ -6601,6 +6614,19 @@ var UITransformer = class _UITransformer {
6601
6614
  if (!retrievedData || retrievedData.length === 0) {
6602
6615
  return this.createTextResponse("No data available", "No relevant data found for your query.");
6603
6616
  }
6617
+ console.log("[UITransformer.transform] Processing retrievedData:", {
6618
+ userQuery,
6619
+ retrievedCount: retrievedData.length,
6620
+ sample: retrievedData.slice(0, 2).map((item) => {
6621
+ var _a3;
6622
+ return {
6623
+ id: item == null ? void 0 : item.id,
6624
+ contentType: typeof (item == null ? void 0 : item.content),
6625
+ contentSnippet: String((_a3 = item == null ? void 0 : item.content) != null ? _a3 : "").substring(0, 150),
6626
+ metadataKeys: Object.keys((item == null ? void 0 : item.metadata) || {})
6627
+ };
6628
+ })
6629
+ });
6604
6630
  const resolvedIntent = intent != null ? intent : this.detectIntentHeuristic(userQuery);
6605
6631
  const filteredData = resolvedIntent.filterInStockOnly ? retrievedData.filter((item) => this.determineStockStatus(item)) : retrievedData;
6606
6632
  const profile = this.profileData(filteredData);
@@ -7090,7 +7116,10 @@ ${schemaProfileText}` : ""}`;
7090
7116
  type: "radar_chart",
7091
7117
  title: "Product Comparison",
7092
7118
  description: `Comparing ${data.length} items across ${radarData.length} attributes`,
7093
- data: radarData.length > 0 ? radarData : data.map((d) => ({ attribute: d.content.substring(0, 40) }))
7119
+ data: radarData.length > 0 ? radarData : data.map((d) => {
7120
+ var _a2;
7121
+ return { attribute: ((_a2 = d == null ? void 0 : d.content) != null ? _a2 : "").substring(0, 40) };
7122
+ })
7094
7123
  };
7095
7124
  }
7096
7125
  static transformToTable(data, query = "") {
@@ -7107,7 +7136,10 @@ ${schemaProfileText}` : ""}`;
7107
7136
  static transformToText(data) {
7108
7137
  return this.createTextResponse(
7109
7138
  "Retrieved Context",
7110
- data.map((item) => item.content).join("\n\n"),
7139
+ data.map((item) => {
7140
+ var _a2;
7141
+ return (_a2 = item == null ? void 0 : item.content) != null ? _a2 : "";
7142
+ }).join("\n\n"),
7111
7143
  `Found ${data.length} relevant results`
7112
7144
  );
7113
7145
  }
@@ -7268,6 +7300,7 @@ ${schemaProfileText}` : ""}`;
7268
7300
  return productTerms && productAction && !nonProductEntityTerms;
7269
7301
  }
7270
7302
  static isProductData(item) {
7303
+ if (!item) return false;
7271
7304
  const content = (item.content || "").toLowerCase();
7272
7305
  const productKeywords = [
7273
7306
  "product",
@@ -7526,12 +7559,12 @@ ${schemaProfileText}` : ""}`;
7526
7559
  }
7527
7560
  static extractTimeSeriesData(data) {
7528
7561
  return data.map((item) => {
7529
- var _a2, _b, _c, _d, _e;
7562
+ var _a2, _b, _c, _d, _e, _f;
7530
7563
  const meta = item.metadata || {};
7531
7564
  return {
7532
7565
  timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
7533
7566
  value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
7534
- label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
7567
+ label: (_f = meta.label) != null ? _f : ((_e = item == null ? void 0 : item.content) != null ? _e : "").substring(0, 50)
7535
7568
  };
7536
7569
  });
7537
7570
  }
@@ -7645,7 +7678,8 @@ ${schemaProfileText}` : ""}`;
7645
7678
  }, query.includes(normalizedField) ? 3 : 0);
7646
7679
  }
7647
7680
  static resolveTableCellValue(item, column) {
7648
- if (column === "Content") return item.content.substring(0, 100);
7681
+ var _a2, _b, _c;
7682
+ if (column === "Content") return ((_a2 = item == null ? void 0 : item.content) != null ? _a2 : "").substring(0, 100);
7649
7683
  const meta = item.metadata || {};
7650
7684
  const normalizedColumn = this.normalizeComparableField(column);
7651
7685
  const exactMetadata = Object.entries(meta).find(
@@ -7656,9 +7690,9 @@ ${schemaProfileText}` : ""}`;
7656
7690
  }
7657
7691
  const aliasValue = this.resolveAliasedTableCell(meta, column);
7658
7692
  if (aliasValue !== void 0) return this.toDisplayValue(aliasValue);
7659
- const contentValue = this.extractContentFieldValue(item.content, column);
7693
+ const contentValue = this.extractContentFieldValue((_b = item == null ? void 0 : item.content) != null ? _b : "", column);
7660
7694
  if (contentValue !== null) return contentValue;
7661
- const aliasContentValue = this.extractAliasedContentFieldValue(item.content, column);
7695
+ const aliasContentValue = this.extractAliasedContentFieldValue((_c = item == null ? void 0 : item.content) != null ? _c : "", column);
7662
7696
  return aliasContentValue != null ? aliasContentValue : "";
7663
7697
  }
7664
7698
  static resolveAliasedTableCell(meta, column) {
@@ -7708,6 +7742,7 @@ ${schemaProfileText}` : ""}`;
7708
7742
  return { inStockCount: inStock, outOfStockCount: outOfStock };
7709
7743
  }
7710
7744
  static determineStockStatus(item) {
7745
+ if (!item) return true;
7711
7746
  const meta = item.metadata || {};
7712
7747
  const stockValue = resolveMetadataValue(meta, "stock");
7713
7748
  if (stockValue !== void 0) {
@@ -7753,35 +7788,64 @@ ${schemaProfileText}` : ""}`;
7753
7788
  return resolveMetadataValue(meta, uiKey);
7754
7789
  }
7755
7790
  static extractProductInfo(item, config, trainedSchema) {
7756
- var _a2;
7791
+ var _a2, _b;
7792
+ if (!item) return null;
7757
7793
  const meta = item.metadata || {};
7794
+ const content = item.content || "";
7758
7795
  const name = this.getDynamicVal(meta, "name", config, trainedSchema);
7759
7796
  const price = this.getDynamicVal(meta, "price", config, trainedSchema);
7760
7797
  const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
7761
7798
  const description = this.cleanProductDescription(
7762
- (_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
7799
+ (_a2 = this.extractProductDescriptionFromContent(content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
7763
7800
  );
7764
7801
  if (name || this.isProductData(item)) {
7765
7802
  let finalName = name ? String(name) : void 0;
7803
+ if (!finalName && content) {
7804
+ const nameMatch = content.match(/(?:Product|Item|Name):\s*([^\n]+)/i);
7805
+ finalName = nameMatch ? nameMatch[1].trim() : (_b = content.split("\n")[0]) == null ? void 0 : _b.substring(0, 60);
7806
+ }
7766
7807
  if (!finalName) {
7767
- const nameMatch = item.content.match(/(?:Product|Item|Name):\s*([^\n]+)/i);
7768
- finalName = nameMatch ? nameMatch[1].trim() : item.content.split("\n")[0].substring(0, 60);
7808
+ console.warn(
7809
+ `[UITransformer] Unable to read product name from metadata or content for item ${item.id}. Defaulting to 'Unnamed Product'.`,
7810
+ { metadataKeys: Object.keys(meta), contentLength: content.length }
7811
+ );
7769
7812
  }
7770
7813
  let finalPrice = typeof price === "number" || typeof price === "string" ? price : void 0;
7771
- if (!finalPrice) {
7772
- const priceMatch = item.content.match(/(?:Price|Cost):\s*\$?([\d,.]+)/i) || item.content.match(/\$\s*([\d,.]+)/);
7814
+ if (!finalPrice && content) {
7815
+ const priceMatch = content.match(/(?:Price|Cost):\s*\$?([\d,.]+)/i) || content.match(/\$\s*([\d,.]+)/);
7773
7816
  if (priceMatch) finalPrice = priceMatch[1].replace(/,/g, "");
7774
7817
  }
7818
+ if (finalPrice === void 0) {
7819
+ console.warn(
7820
+ `[UITransformer] Unable to read product price from metadata or content for item ${item.id}.`,
7821
+ { metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
7822
+ );
7823
+ }
7775
7824
  const imageValue = this.getDynamicVal(meta, "image", config, trainedSchema);
7825
+ if (!imageValue) {
7826
+ console.debug(
7827
+ `[UITransformer] Unable to read product image URL from metadata for item ${item.id}.`
7828
+ );
7829
+ }
7830
+ if (!description) {
7831
+ console.debug(
7832
+ `[UITransformer] Unable to read product description from metadata or content for item ${item.id}.`
7833
+ );
7834
+ }
7776
7835
  return {
7777
7836
  id: item.id,
7778
- name: finalName,
7837
+ name: finalName || "Unnamed Product",
7779
7838
  price: finalPrice,
7780
7839
  image: typeof imageValue === "string" ? imageValue : void 0,
7781
7840
  brand: brand ? String(brand) : void 0,
7782
7841
  description,
7783
7842
  inStock: this.determineStockStatus(item)
7784
7843
  };
7844
+ } else {
7845
+ console.warn(
7846
+ `[UITransformer] Item ${item.id} skipped: unable to read name or identify as product data from metadata/content.`,
7847
+ { metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
7848
+ );
7785
7849
  }
7786
7850
  return null;
7787
7851
  }
@@ -7866,13 +7930,13 @@ RULES:
7866
7930
  5. If no relevant data is found, return text: "I cannot answer this question based on the available information."`;
7867
7931
  }
7868
7932
  static buildContextSummary(sources, maxChars = 6e3) {
7869
- const items = sources.map((s, i) => {
7933
+ const items = (sources || []).filter(Boolean).map((s, i) => {
7870
7934
  var _a2, _b, _c, _d;
7871
7935
  return {
7872
7936
  index: i + 1,
7873
- content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
7874
- metadata: (_c = s.metadata) != null ? _c : {},
7875
- score: (_d = s.score) != null ? _d : 0
7937
+ content: (_b = (_a2 = s == null ? void 0 : s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
7938
+ metadata: (_c = s == null ? void 0 : s.metadata) != null ? _c : {},
7939
+ score: (_d = s == null ? void 0 : s.score) != null ? _d : 0
7876
7940
  };
7877
7941
  });
7878
7942
  const full = JSON.stringify(items, null, 2);
@@ -8441,17 +8505,33 @@ ${m.content}`).join("\n\n---\n\n");
8441
8505
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
8442
8506
  const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
8443
8507
  const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
8444
- const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
8508
+ const rawSources = ((strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : []).filter((s) => Boolean(s && typeof s === "object"));
8509
+ console.log("[Pipeline] Raw vectorDB.query response:", {
8510
+ rawCount: rawSources.length,
8511
+ sample: rawSources.slice(0, 2).map((s) => {
8512
+ var _a3;
8513
+ return {
8514
+ id: s == null ? void 0 : s.id,
8515
+ score: s == null ? void 0 : s.score,
8516
+ contentType: typeof (s == null ? void 0 : s.content),
8517
+ contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
8518
+ metadataKeys: Object.keys((s == null ? void 0 : s.metadata) || {})
8519
+ };
8520
+ })
8521
+ });
8445
8522
  const retrieveEnd = performance.now();
8446
8523
  const embedMs = retrieveEnd - embedStart;
8447
8524
  const retrieveMs = retrieveEnd - embedStart;
8448
8525
  const rerankStart = performance.now();
8449
- const structuredSources = this.applyStructuredFilters(rawSources, filter);
8450
- let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => m.score >= scoreThreshold);
8526
+ const structuredSources = this.applyStructuredFilters(rawSources, filter).filter((s) => Boolean(s && typeof s === "object"));
8527
+ let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => {
8528
+ var _a3;
8529
+ return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= scoreThreshold;
8530
+ });
8451
8531
  const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
8452
8532
  const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
8453
8533
  if (!hasNumericPredicates && useReranking) {
8454
- fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
8534
+ fullSources = (yield new __await(this.reranker.rerank(fullSources, question, rerankLimit))).filter((s) => Boolean(s && typeof s === "object"));
8455
8535
  } else if (!wantsExhaustiveList) {
8456
8536
  fullSources = fullSources.slice(0, topK);
8457
8537
  }
@@ -8466,13 +8546,33 @@ ${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
8466
8546
  displayCount = fullSources.length;
8467
8547
  } else {
8468
8548
  const baseThreshold = Math.max(scoreThreshold, 0.4);
8469
- const highlyRelevant = fullSources.filter((m) => m.score >= baseThreshold);
8549
+ const highlyRelevant = fullSources.filter((m) => {
8550
+ var _a3;
8551
+ return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= baseThreshold;
8552
+ });
8470
8553
  displayCount = Math.max(highlyRelevant.length, topK);
8471
8554
  if (displayCount > 15) {
8472
8555
  displayCount = 15;
8473
8556
  }
8474
8557
  }
8475
- const sources = [...fullSources].sort((a, b) => b.score - a.score).slice(0, displayCount);
8558
+ const sources = [...fullSources].filter((s) => Boolean(s && typeof s === "object")).sort((a, b) => {
8559
+ var _a3, _b2;
8560
+ return ((_a3 = b == null ? void 0 : b.score) != null ? _a3 : 0) - ((_b2 = a == null ? void 0 : a.score) != null ? _b2 : 0);
8561
+ }).slice(0, displayCount);
8562
+ console.log("[Pipeline] Final sources for prompt & UI:", {
8563
+ count: sources.length,
8564
+ sources: sources.map((s, idx) => {
8565
+ var _a3;
8566
+ return {
8567
+ rank: idx + 1,
8568
+ id: s == null ? void 0 : s.id,
8569
+ score: s == null ? void 0 : s.score,
8570
+ contentType: typeof (s == null ? void 0 : s.content),
8571
+ contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
8572
+ metadata: s == null ? void 0 : s.metadata
8573
+ };
8574
+ })
8575
+ });
8476
8576
  if (graphData && graphData.nodes.length > 0) {
8477
8577
  const graphContext = graphData.nodes.map(
8478
8578
  (n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
@@ -8498,18 +8598,18 @@ ${context}`;
8498
8598
  }
8499
8599
  yield {
8500
8600
  reply: "",
8501
- sources: sources.map((s) => {
8502
- var _a3;
8601
+ sources: (sources || []).filter((s) => Boolean(s && typeof s === "object")).map((s) => {
8602
+ var _a3, _b2, _c2;
8503
8603
  return {
8504
8604
  id: s.id,
8505
- score: s.score,
8506
- content: s.content,
8507
- metadata: (_a3 = s.metadata) != null ? _a3 : {},
8605
+ score: (_a3 = s.score) != null ? _a3 : 0,
8606
+ content: (_b2 = s == null ? void 0 : s.content) != null ? _b2 : "",
8607
+ metadata: (_c2 = s == null ? void 0 : s.metadata) != null ? _c2 : {},
8508
8608
  namespace: ns
8509
8609
  };
8510
8610
  })
8511
8611
  };
8512
- const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
8612
+ const allMetadataKeys = Array.from(new Set(sources.filter(Boolean).flatMap((s) => Object.keys((s == null ? void 0 : s.metadata) || {}))));
8513
8613
  const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
8514
8614
  if (allMetadataKeys.length > 0 && !cachedSchema) {
8515
8615
  SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
@@ -8801,6 +8901,8 @@ ${context}`;
8801
8901
  });
8802
8902
  }
8803
8903
  resolveNumericPredicateValue(source, predicate) {
8904
+ var _a2;
8905
+ if (!source) return null;
8804
8906
  const meta = source.metadata || {};
8805
8907
  const field = predicate.field;
8806
8908
  const entries = Object.entries(meta).filter(([, value]) => value !== null && value !== void 0 && typeof value !== "object");
@@ -8812,7 +8914,7 @@ ${context}`;
8812
8914
  const value = this.toFiniteNumber(Array.isArray(fuzzy) ? fuzzy[1] : fuzzy.value);
8813
8915
  if (value !== null) return value;
8814
8916
  }
8815
- const contentValue = this.extractNumericValueFromContent(source.content, field);
8917
+ const contentValue = this.extractNumericValueFromContent((_a2 = source.content) != null ? _a2 : "", field);
8816
8918
  if (contentValue !== null) return contentValue;
8817
8919
  }
8818
8920
  for (const [key, value] of entries) {
@@ -8823,6 +8925,7 @@ ${context}`;
8823
8925
  return null;
8824
8926
  }
8825
8927
  extractNumericValueFromContent(content, field) {
8928
+ if (!content || typeof content !== "string") return null;
8826
8929
  const escapedWords = field.split(/\s+|_+|-+/).filter(Boolean).map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
8827
8930
  if (escapedWords.length === 0) return null;
8828
8931
  const pattern = new RegExp(`(?:${escapedWords.join("[\\\\s_:-]*")})\\s*[:\\-\u2013]?\\s*([\\d,]+(?:\\.\\d+)?)`, "i");
@@ -8908,6 +9011,20 @@ ${context}`;
8908
9011
  resolvedSources.push(source);
8909
9012
  }
8910
9013
  }
9014
+ console.log("[Pipeline] retrieve() response:", {
9015
+ query,
9016
+ namespace: ns,
9017
+ count: resolvedSources.length,
9018
+ sample: resolvedSources.slice(0, 2).map((s) => {
9019
+ var _a3;
9020
+ return {
9021
+ id: s == null ? void 0 : s.id,
9022
+ score: s == null ? void 0 : s.score,
9023
+ contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
9024
+ metadata: s == null ? void 0 : s.metadata
9025
+ };
9026
+ })
9027
+ });
8911
9028
  return { sources: resolvedSources, graphData };
8912
9029
  }
8913
9030
  /** Rewrite the user query for better retrieval performance. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
5
5
  "author": "Abhinav Alkuchi",
6
6
  "license": "UNLICENSED",
@@ -583,9 +583,20 @@ You are a helpful assistant. Use the provided context to answer questions accura
583
583
  const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
584
584
  const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
585
585
 
586
- const rawSources = (strategyResult === 'vector' || strategyResult === 'both') && queryVector && queryVector.length > 0
586
+ const rawSources = ((strategyResult === 'vector' || strategyResult === 'both') && queryVector && queryVector.length > 0
587
587
  ? await this.vectorDB.query(queryVector, retrievalLimit, ns, filter)
588
- : [];
588
+ : []).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
589
+
590
+ console.log('[Pipeline] Raw vectorDB.query response:', {
591
+ rawCount: rawSources.length,
592
+ sample: rawSources.slice(0, 2).map((s) => ({
593
+ id: s?.id,
594
+ score: s?.score,
595
+ contentType: typeof s?.content,
596
+ contentSnippet: String(s?.content ?? '').substring(0, 150),
597
+ metadataKeys: Object.keys(s?.metadata || {}),
598
+ })),
599
+ });
589
600
 
590
601
  const retrieveEnd = performance.now();
591
602
  const embedMs = retrieveEnd - embedStart;
@@ -593,14 +604,14 @@ You are a helpful assistant. Use the provided context to answer questions accura
593
604
 
594
605
  // 3. Reranking
595
606
  const rerankStart = performance.now();
596
- const structuredSources = this.applyStructuredFilters(rawSources, filter);
607
+ const structuredSources = this.applyStructuredFilters(rawSources, filter).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
597
608
  let fullSources = hasNumericPredicates
598
609
  ? structuredSources
599
- : structuredSources.filter((m) => m.score >= scoreThreshold);
610
+ : structuredSources.filter((m) => (m?.score ?? 0) >= scoreThreshold);
600
611
  const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
601
612
  const useReranking = arch !== 'naive' && (arch === 'retrieve-and-rerank' || this.config.rag?.useReranking);
602
613
  if (!hasNumericPredicates && useReranking) {
603
- fullSources = await this.reranker.rerank(fullSources, question, rerankLimit);
614
+ fullSources = (await this.reranker.rerank(fullSources, question, rerankLimit)).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
604
615
  } else if (!wantsExhaustiveList) {
605
616
  fullSources = fullSources.slice(0, topK);
606
617
  }
@@ -620,7 +631,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
620
631
  } else {
621
632
  // For general semantic queries, count the number of matches meeting high relevance threshold
622
633
  const baseThreshold = Math.max(scoreThreshold, 0.4);
623
- const highlyRelevant = fullSources.filter(m => m.score >= baseThreshold);
634
+ const highlyRelevant = fullSources.filter(m => (m?.score ?? 0) >= baseThreshold);
624
635
  displayCount = Math.max(highlyRelevant.length, topK);
625
636
  // Cap non-metadata semantic searches to a maximum of 15 to keep the UI clean
626
637
  if (displayCount > 15) {
@@ -630,9 +641,22 @@ You are a helpful assistant. Use the provided context to answer questions accura
630
641
 
631
642
  // Ensure they are sorted from highest to lowest score, then slice using our dynamic count
632
643
  const sources = [...fullSources]
633
- .sort((a, b) => b.score - a.score)
644
+ .filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'))
645
+ .sort((a, b) => (b?.score ?? 0) - (a?.score ?? 0))
634
646
  .slice(0, displayCount);
635
647
 
648
+ console.log('[Pipeline] Final sources for prompt & UI:', {
649
+ count: sources.length,
650
+ sources: sources.map((s, idx) => ({
651
+ rank: idx + 1,
652
+ id: s?.id,
653
+ score: s?.score,
654
+ contentType: typeof s?.content,
655
+ contentSnippet: String(s?.content ?? '').substring(0, 150),
656
+ metadata: s?.metadata,
657
+ })),
658
+ });
659
+
636
660
  if (graphData && graphData.nodes.length > 0) {
637
661
  const graphContext = graphData.nodes.map(n =>
638
662
  `Entity: ${n.label} (${n.id})${n.properties ? ' - ' + JSON.stringify(n.properties) : ''}`
@@ -653,17 +677,17 @@ You are a helpful assistant. Use the provided context to answer questions accura
653
677
  // Yield sources immediately to support early UI citation rendering (highly responsive)
654
678
  yield {
655
679
  reply: '',
656
- sources: sources.map((s) => ({
680
+ sources: (sources || []).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object')).map((s) => ({
657
681
  id: s.id,
658
- score: s.score,
659
- content: s.content,
660
- metadata: s.metadata ?? {},
682
+ score: s.score ?? 0,
683
+ content: s?.content ?? '',
684
+ metadata: s?.metadata ?? {},
661
685
  namespace: ns,
662
686
  } satisfies RetrievedChunk)),
663
687
  } as ChatResponse;
664
688
 
665
689
  // 4.5 Schema Training — true fire-and-forget, never gates anything.
666
- const allMetadataKeys = Array.from(new Set(sources.flatMap(s => Object.keys(s.metadata || {}))));
690
+ const allMetadataKeys = Array.from(new Set(sources.filter(Boolean).flatMap(s => Object.keys(s?.metadata || {}))));
667
691
  const cachedSchema = allMetadataKeys.length > 0
668
692
  ? SchemaMapper.getCached(ns, allMetadataKeys)
669
693
  : undefined;
@@ -1015,6 +1039,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
1015
1039
  }
1016
1040
 
1017
1041
  private resolveNumericPredicateValue(source: VectorMatch, predicate: NumericPredicate): number | null {
1042
+ if (!source) return null;
1018
1043
  const meta = source.metadata || {};
1019
1044
  const field = predicate.field;
1020
1045
  const entries = Object.entries(meta)
@@ -1032,7 +1057,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
1032
1057
  if (value !== null) return value;
1033
1058
  }
1034
1059
 
1035
- const contentValue = this.extractNumericValueFromContent(source.content, field);
1060
+ const contentValue = this.extractNumericValueFromContent(source.content ?? '', field);
1036
1061
  if (contentValue !== null) return contentValue;
1037
1062
  }
1038
1063
 
@@ -1046,6 +1071,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
1046
1071
  }
1047
1072
 
1048
1073
  private extractNumericValueFromContent(content: string, field: string): number | null {
1074
+ if (!content || typeof content !== 'string') return null;
1049
1075
  const escapedWords = field
1050
1076
  .split(/\s+|_+|-+/)
1051
1077
  .filter(Boolean)
@@ -1164,6 +1190,18 @@ You are a helpful assistant. Use the provided context to answer questions accura
1164
1190
  }
1165
1191
  }
1166
1192
 
1193
+ console.log('[Pipeline] retrieve() response:', {
1194
+ query,
1195
+ namespace: ns,
1196
+ count: resolvedSources.length,
1197
+ sample: resolvedSources.slice(0, 2).map((s) => ({
1198
+ id: s?.id,
1199
+ score: s?.score,
1200
+ contentSnippet: String(s?.content ?? '').substring(0, 150),
1201
+ metadata: s?.metadata,
1202
+ })),
1203
+ });
1204
+
1167
1205
  return { sources: resolvedSources, graphData };
1168
1206
  }
1169
1207
 
@@ -360,10 +360,10 @@ Return ONLY 'vector', 'graph', or 'both'. No explanation.`;
360
360
  { temperature: 0, maxTokens: 10 }
361
361
  );
362
362
 
363
- const cleanResponse = response.trim().toLowerCase();
364
- if (cleanResponse.includes('vector')) return 'vector';
365
- if (cleanResponse.includes('graph')) return 'graph';
363
+ const cleanResponse = (response ?? '').trim().toLowerCase();
366
364
  if (cleanResponse.includes('both')) return 'both';
365
+ if (cleanResponse.includes('graph')) return 'graph';
366
+ if (cleanResponse.includes('vector')) return 'vector';
367
367
  } catch (error) {
368
368
  console.warn('[QueryProcessor] LLM strategy classification failed, falling back to keywords:', error);
369
369
  }