@retrivora-ai/rag-engine 1.8.9 → 1.9.1

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 (44) hide show
  1. package/dist/{ILLMProvider-CbUtvWAW.d.mts → ILLMProvider-BQyKZLnd.d.mts} +10 -2
  2. package/dist/{ILLMProvider-CbUtvWAW.d.ts → ILLMProvider-BQyKZLnd.d.ts} +10 -2
  3. package/dist/handlers/index.d.mts +2 -2
  4. package/dist/handlers/index.d.ts +2 -2
  5. package/dist/handlers/index.js +1726 -522
  6. package/dist/handlers/index.mjs +1725 -521
  7. package/dist/{index-DgzcnqZs.d.ts → index-A0GqPsaG.d.ts} +1 -1
  8. package/dist/{index-c_y_5qdw.d.mts → index-CDftK3qs.d.mts} +1 -1
  9. package/dist/index.css +26 -0
  10. package/dist/index.d.mts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +246 -76
  13. package/dist/index.mjs +248 -76
  14. package/dist/server.d.mts +32 -5
  15. package/dist/server.d.ts +32 -5
  16. package/dist/server.js +1735 -733
  17. package/dist/server.mjs +1733 -731
  18. package/package.json +1 -1
  19. package/src/components/MarkdownComponents.tsx +3 -3
  20. package/src/components/MessageBubble.tsx +49 -2
  21. package/src/components/ProductCard.tsx +33 -6
  22. package/src/components/UIDispatcher.tsx +1 -0
  23. package/src/components/VisualizationRenderer.tsx +143 -11
  24. package/src/config/EmbeddingStrategy.ts +5 -4
  25. package/src/config/RagConfig.ts +10 -2
  26. package/src/config/serverConfig.ts +16 -1
  27. package/src/core/LLMRouter.ts +79 -0
  28. package/src/core/Pipeline.ts +262 -45
  29. package/src/core/ProviderRegistry.ts +6 -0
  30. package/src/core/QueryProcessor.ts +98 -0
  31. package/src/handlers/index.ts +8 -5
  32. package/src/hooks/useRagChat.ts +53 -17
  33. package/src/llm/providers/UniversalLLMAdapter.ts +110 -13
  34. package/src/providers/vectordb/ChromaDBProvider.ts +13 -6
  35. package/src/providers/vectordb/MilvusProvider.ts +18 -2
  36. package/src/providers/vectordb/MultiTablePostgresProvider.ts +16 -29
  37. package/src/providers/vectordb/PostgreSQLProvider.ts +4 -15
  38. package/src/providers/vectordb/QdrantProvider.ts +2 -5
  39. package/src/providers/vectordb/RedisProvider.ts +3 -4
  40. package/src/providers/vectordb/WeaviateProvider.ts +41 -3
  41. package/src/types/index.ts +26 -0
  42. package/src/utils/ProductExtractor.ts +5 -3
  43. package/src/utils/UITransformer.ts +1345 -534
  44. package/src/utils/synonyms.ts +2 -0
package/dist/index.mjs CHANGED
@@ -368,7 +368,20 @@ import { ChevronLeft, ChevronRight } from "lucide-react";
368
368
  import Image from "next/image";
369
369
  import { ShoppingCart, ExternalLink } from "lucide-react";
370
370
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
371
+ function cleanProductDescription(raw) {
372
+ var _a;
373
+ if (raw === null || raw === void 0) return "";
374
+ const source = String(raw);
375
+ const bodyMatch = source.match(
376
+ /\bBody\s*\(HTML\)\s*:\s*([\s\S]*?)(?=\s*[,.]?\s+\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\b\s*:|$)/i
377
+ );
378
+ const descriptionMatch = bodyMatch != null ? bodyMatch : source.match(
379
+ /\b(?:Description|Summary|Details|Body)\s*:\s*([\s\S]*?)(?=\s*[,.]?\s+\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\b\s*:|$)/i
380
+ );
381
+ return ((_a = descriptionMatch == null ? void 0 : descriptionMatch[1]) != null ? _a : source).replace(/<[^>]*>/g, " ").replace(/&nbsp;/gi, " ").replace(/&amp;/gi, "&").replace(/&quot;/gi, '"').replace(/&#39;/gi, "'").replace(/\[[^\]]*TYPE[^\]]*\]/gi, " ").replace(/\b(?:Handle|Title|Vendor|Type|Tags|Published|Option\d*\s+Name|Option\d*\s+Value|Option|Variant|Image|SKU|Price|Status|Category)\s*:\s*[^,.\n:]+[,.]?/gi, " ").replace(/\bBody\s*\(HTML\)\s*:\s*/gi, " ").replace(/\b(?:Description|Summary|Details|Body|Content)\s*:\s*/gi, " ").replace(/\s+/g, " ").trim();
382
+ }
371
383
  function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
384
+ const description = cleanProductDescription(product.description);
372
385
  return /* @__PURE__ */ jsxs3("div", { className: "flex-shrink-0 w-full bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 rounded-xl overflow-hidden shadow-sm hover:shadow-md transition-all duration-300 group", children: [
373
386
  /* @__PURE__ */ jsxs3("div", { className: "relative h-40 w-full bg-slate-100 dark:bg-white/5 flex items-center justify-center overflow-hidden", children: [
374
387
  product.image ? /* @__PURE__ */ jsx4(
@@ -380,7 +393,7 @@ function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
380
393
  unoptimized: true,
381
394
  className: "object-cover group-hover:scale-105 transition-transform duration-500"
382
395
  }
383
- ) : /* @__PURE__ */ jsx4("div", { className: "text-slate-400 dark:text-white/20", children: /* @__PURE__ */ jsx4(ShoppingCart, { className: "w-12 h-12" }) }),
396
+ ) : /* @__PURE__ */ jsx4("div", { className: "text-slate-400 dark:text-white/20 cursor-pointer", onClick: () => onAddToCart == null ? void 0 : onAddToCart(product), children: /* @__PURE__ */ jsx4(ShoppingCart, { className: "w-12 h-12" }) }),
384
397
  product.brand && /* @__PURE__ */ jsx4("div", { className: "absolute top-2 left-2 px-2 py-1 bg-white/90 dark:bg-black/60 backdrop-blur-md rounded-md text-[10px] font-bold uppercase tracking-wider text-slate-700 dark:text-white/90 shadow-sm", children: product.brand })
385
398
  ] }),
386
399
  /* @__PURE__ */ jsxs3("div", { className: "p-4 flex flex-col gap-2", children: [
@@ -388,13 +401,13 @@ function ProductCard({ product, primaryColor = "#6366f1", onAddToCart }) {
388
401
  /* @__PURE__ */ jsx4("h3", { className: "text-sm font-semibold text-slate-800 dark:text-white/90 line-clamp-1", children: product.name }),
389
402
  product.price && /* @__PURE__ */ jsx4("span", { className: "text-sm font-bold", style: { color: primaryColor }, children: typeof product.price === "number" ? `$${product.price}` : String(product.price).match(/^[\d.]/) ? `$${product.price}` : product.price })
390
403
  ] }),
391
- product.description && /* @__PURE__ */ jsx4("p", { className: "text-[11px] text-slate-500 dark:text-white/50 line-clamp-2 leading-relaxed", children: product.description }),
404
+ description && /* @__PURE__ */ jsx4("p", { className: "text-[11px] text-slate-500 dark:text-white/50 line-clamp-2 leading-relaxed", children: description }),
392
405
  /* @__PURE__ */ jsxs3("div", { className: "mt-2 flex gap-2", children: [
393
406
  /* @__PURE__ */ jsxs3(
394
407
  "button",
395
408
  {
396
409
  onClick: () => onAddToCart == null ? void 0 : onAddToCart(product),
397
- className: "flex-1 py-2 px-3 rounded-lg text-[11px] font-medium text-white shadow-sm hover:opacity-90 transition-opacity flex items-center justify-center gap-1.5",
410
+ className: "flex-1 py-2 px-3 rounded-lg text-[11px] font-medium text-white shadow-sm hover:opacity-90 transition-opacity flex items-center justify-center gap-1.5 cursor-pointer",
398
411
  style: { background: primaryColor },
399
412
  children: [
400
413
  /* @__PURE__ */ jsx4(ShoppingCart, { className: "w-3 h-3" }),
@@ -503,6 +516,8 @@ import {
503
516
  Bar as Bar2,
504
517
  LineChart as LineChart2,
505
518
  Line as Line2,
519
+ ScatterChart,
520
+ Scatter,
506
521
  XAxis as XAxis2,
507
522
  YAxis as YAxis2,
508
523
  CartesianGrid as CartesianGrid2,
@@ -726,6 +741,9 @@ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-run
726
741
  function getColor(index) {
727
742
  return CHART_COLORS[index % CHART_COLORS.length];
728
743
  }
744
+ function stripLeakedAnswerWrappers(raw) {
745
+ return raw.replace(/<prose\s+answer(?:\s+in\s+[^>]*)?>\s*([\s\S]*?)\s*<\/prose>/gi, "$1").replace(/<\/?prose(?:\s+answer)?[^>]*>/gi, "").trim();
746
+ }
729
747
  function CustomTooltip({
730
748
  active,
731
749
  payload,
@@ -775,10 +793,20 @@ function renderVisualization(type, data, onAddToCart, primaryColor, isStreaming)
775
793
  return /* @__PURE__ */ jsx7(PieChartView, { data, isStreaming });
776
794
  case "bar_chart":
777
795
  return /* @__PURE__ */ jsx7(BarChartView, { data, primaryColor, isStreaming });
796
+ case "histogram":
797
+ return /* @__PURE__ */ jsx7(BarChartView, { data, primaryColor, isStreaming });
798
+ case "horizontal_bar":
799
+ return /* @__PURE__ */ jsx7(BarChartView, { data, primaryColor, isStreaming, layout: "vertical" });
778
800
  case "line_chart":
779
801
  return /* @__PURE__ */ jsx7(LineChartView, { data, primaryColor, isStreaming });
802
+ case "scatter_plot":
803
+ return /* @__PURE__ */ jsx7(ScatterPlotView, { data, primaryColor, isStreaming });
780
804
  case "radar_chart":
781
805
  return /* @__PURE__ */ jsx7(RadarChartView, { data, isStreaming });
806
+ case "metric_card":
807
+ return /* @__PURE__ */ jsx7(MetricCardView, { data, isStreaming });
808
+ case "geo_map":
809
+ return /* @__PURE__ */ jsx7(BarChartView, { data, primaryColor, isStreaming });
782
810
  case "table":
783
811
  return /* @__PURE__ */ jsx7(TableView, { data, isStreaming });
784
812
  case "product_carousel":
@@ -813,28 +841,74 @@ function PieChartView({ data, isStreaming }) {
813
841
  }
814
842
  const chartData = data.map((item) => ({
815
843
  name: item.label,
816
- value: item.value
844
+ value: item.value,
845
+ inStockCount: item.inStockCount,
846
+ outOfStockCount: item.outOfStockCount
817
847
  }));
818
- return /* @__PURE__ */ jsx7("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ jsx7(ResponsiveContainer2, { width: "100%", height: 280, children: /* @__PURE__ */ jsxs6(PieChart2, { children: [
819
- /* @__PURE__ */ jsx7(
820
- Pie2,
821
- {
822
- data: chartData,
823
- dataKey: "value",
824
- nameKey: "name",
825
- cx: "50%",
826
- cy: "50%",
827
- outerRadius: "68%",
828
- label: false,
829
- labelLine: false,
830
- children: chartData.map((_entry, index) => /* @__PURE__ */ jsx7(Cell2, { fill: getColor(index) }, `cell-${index}`))
831
- }
832
- ),
833
- /* @__PURE__ */ jsx7(Tooltip2, { content: /* @__PURE__ */ jsx7(CustomTooltip, {}) }),
834
- /* @__PURE__ */ jsx7(Legend2, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })
835
- ] }) }) });
848
+ const hasStockBreakdown = chartData.some(
849
+ (item) => item.inStockCount !== void 0 || item.outOfStockCount !== void 0
850
+ );
851
+ return /* @__PURE__ */ jsxs6("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: [
852
+ /* @__PURE__ */ jsx7(ResponsiveContainer2, { width: "100%", height: 280, children: /* @__PURE__ */ jsxs6(PieChart2, { children: [
853
+ /* @__PURE__ */ jsx7(
854
+ Pie2,
855
+ {
856
+ data: chartData,
857
+ dataKey: "value",
858
+ nameKey: "name",
859
+ cx: "50%",
860
+ cy: "50%",
861
+ outerRadius: "68%",
862
+ label: false,
863
+ labelLine: false,
864
+ children: chartData.map((_entry, index) => /* @__PURE__ */ jsx7(Cell2, { fill: getColor(index) }, `cell-${index}`))
865
+ }
866
+ ),
867
+ /* @__PURE__ */ jsx7(Tooltip2, { content: /* @__PURE__ */ jsx7(CustomTooltip, {}) }),
868
+ /* @__PURE__ */ jsx7(Legend2, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })
869
+ ] }) }),
870
+ hasStockBreakdown && /* @__PURE__ */ jsx7("div", { className: "mt-3 grid gap-2 sm:grid-cols-2", children: chartData.map((item, index) => {
871
+ var _a, _b;
872
+ const inStock = Number((_a = item.inStockCount) != null ? _a : 0);
873
+ const outOfStock = Number((_b = item.outOfStockCount) != null ? _b : 0);
874
+ const status = inStock > 0 ? `${inStock} in stock` : "Out of stock";
875
+ const mutedStatus = outOfStock > 0 ? `${outOfStock} out` : null;
876
+ return /* @__PURE__ */ jsxs6(
877
+ "div",
878
+ {
879
+ className: "flex min-w-0 items-center justify-between gap-3 rounded-md border border-slate-100 px-2.5 py-2 text-xs dark:border-white/10",
880
+ children: [
881
+ /* @__PURE__ */ jsxs6("span", { className: "flex min-w-0 items-center gap-2 text-slate-700 dark:text-white/75", children: [
882
+ /* @__PURE__ */ jsx7(
883
+ "span",
884
+ {
885
+ className: "h-2.5 w-2.5 flex-shrink-0 rounded-full",
886
+ style: { background: getColor(index) }
887
+ }
888
+ ),
889
+ /* @__PURE__ */ jsx7("span", { className: "truncate", children: item.name })
890
+ ] }),
891
+ /* @__PURE__ */ jsxs6("span", { className: inStock > 0 ? "whitespace-nowrap font-medium text-emerald-600" : "whitespace-nowrap font-medium text-rose-600", children: [
892
+ status,
893
+ mutedStatus && /* @__PURE__ */ jsxs6("span", { className: "ml-1 text-slate-400", children: [
894
+ "(",
895
+ mutedStatus,
896
+ ")"
897
+ ] })
898
+ ] })
899
+ ]
900
+ },
901
+ item.name
902
+ );
903
+ }) })
904
+ ] });
836
905
  }
837
- function BarChartView({ data, primaryColor, isStreaming }) {
906
+ function BarChartView({
907
+ data,
908
+ primaryColor,
909
+ isStreaming,
910
+ layout = "horizontal"
911
+ }) {
838
912
  if (isStreaming) return /* @__PURE__ */ jsx7(ChartSkeleton, { type: "bar" });
839
913
  if (!Array.isArray(data) || data.length === 0) {
840
914
  return /* @__PURE__ */ jsx7("div", { className: "text-xs text-red-500", children: "Invalid bar chart data" });
@@ -845,26 +919,66 @@ function BarChartView({ data, primaryColor, isStreaming }) {
845
919
  }, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
846
920
  const barColor = primaryColor != null ? primaryColor : getColor(0);
847
921
  const hasStock = chartData.some((d) => "inStockCount" in d);
848
- return /* @__PURE__ */ jsx7("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ jsx7(ResponsiveContainer2, { width: "100%", height: 260, children: /* @__PURE__ */ jsxs6(BarChart2, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 }, children: [
849
- /* @__PURE__ */ jsx7(CartesianGrid2, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
850
- /* @__PURE__ */ jsx7(
851
- XAxis2,
852
- {
853
- dataKey: "category",
854
- tick: { fontSize: 11, fill: "#64748b" },
855
- tickLine: false,
856
- axisLine: { stroke: "#cbd5e1" }
857
- }
858
- ),
859
- /* @__PURE__ */ jsx7(YAxis2, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }),
860
- /* @__PURE__ */ jsx7(Tooltip2, { content: /* @__PURE__ */ jsx7(CustomTooltip, {}), cursor: { fill: "#f1f5f9" } }),
861
- /* @__PURE__ */ jsx7(Legend2, { wrapperStyle: { fontSize: 12 } }),
862
- hasStock ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
863
- /* @__PURE__ */ jsx7(Bar2, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }),
864
- /* @__PURE__ */ jsx7(Bar2, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })
865
- ] }) : /* @__PURE__ */ jsx7(Bar2, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] })
922
+ return /* @__PURE__ */ jsx7("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ jsx7(ResponsiveContainer2, { width: "100%", height: 260, children: /* @__PURE__ */ jsxs6(
923
+ BarChart2,
924
+ {
925
+ data: chartData,
926
+ layout,
927
+ margin: { top: 10, right: 10, left: layout === "vertical" ? 20 : -20, bottom: 0 },
928
+ children: [
929
+ /* @__PURE__ */ jsx7(CartesianGrid2, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }),
930
+ layout === "vertical" ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
931
+ /* @__PURE__ */ jsx7(XAxis2, { type: "number", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }),
932
+ /* @__PURE__ */ jsx7(YAxis2, { type: "category", dataKey: "category", width: 110, tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false })
933
+ ] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
934
+ /* @__PURE__ */ jsx7(
935
+ XAxis2,
936
+ {
937
+ dataKey: "category",
938
+ tick: { fontSize: 11, fill: "#64748b" },
939
+ tickLine: false,
940
+ axisLine: { stroke: "#cbd5e1" }
941
+ }
942
+ ),
943
+ /* @__PURE__ */ jsx7(YAxis2, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false })
944
+ ] }),
945
+ /* @__PURE__ */ jsx7(Tooltip2, { content: /* @__PURE__ */ jsx7(CustomTooltip, {}), cursor: { fill: "#f1f5f9" } }),
946
+ /* @__PURE__ */ jsx7(Legend2, { wrapperStyle: { fontSize: 12 } }),
947
+ hasStock ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
948
+ /* @__PURE__ */ jsx7(Bar2, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }),
949
+ /* @__PURE__ */ jsx7(Bar2, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })
950
+ ] }) : /* @__PURE__ */ jsx7(Bar2, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] })
951
+ ]
952
+ }
953
+ ) }) });
954
+ }
955
+ function ScatterPlotView({ data, primaryColor, isStreaming }) {
956
+ if (isStreaming) return /* @__PURE__ */ jsx7(ChartSkeleton, { type: "bar" });
957
+ if (!Array.isArray(data) || data.length === 0) {
958
+ return /* @__PURE__ */ jsx7("div", { className: "text-xs text-red-500", children: "Invalid scatter plot data" });
959
+ }
960
+ return /* @__PURE__ */ jsx7("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto", children: /* @__PURE__ */ jsx7(ResponsiveContainer2, { width: "100%", height: 260, children: /* @__PURE__ */ jsxs6(ScatterChart, { margin: { top: 10, right: 10, left: -20, bottom: 0 }, children: [
961
+ /* @__PURE__ */ jsx7(CartesianGrid2, { strokeDasharray: "3 3", stroke: "#e2e8f0" }),
962
+ /* @__PURE__ */ jsx7(XAxis2, { type: "number", dataKey: "x", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }),
963
+ /* @__PURE__ */ jsx7(YAxis2, { type: "number", dataKey: "y", tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }),
964
+ /* @__PURE__ */ jsx7(Tooltip2, { content: /* @__PURE__ */ jsx7(CustomTooltip, {}), cursor: { strokeDasharray: "3 3" } }),
965
+ /* @__PURE__ */ jsx7(Scatter, { name: "Value", data, fill: primaryColor != null ? primaryColor : getColor(0) })
866
966
  ] }) }) });
867
967
  }
968
+ function MetricCardView({ data, isStreaming }) {
969
+ if (isStreaming) return /* @__PURE__ */ jsx7(ChartSkeleton, { type: "bar" });
970
+ if (!data || typeof data.value !== "number") {
971
+ return /* @__PURE__ */ jsx7("div", { className: "text-xs text-red-500", children: "Invalid metric data" });
972
+ }
973
+ return /* @__PURE__ */ jsxs6("div", { className: "rounded-xl border border-slate-200 bg-white p-4 shadow-sm dark:border-white/10 dark:bg-slate-900", children: [
974
+ /* @__PURE__ */ jsx7("div", { className: "text-xs font-medium uppercase text-slate-500 dark:text-slate-400", children: data.label }),
975
+ /* @__PURE__ */ jsxs6("div", { className: "mt-2 text-3xl font-semibold text-slate-900 dark:text-white", children: [
976
+ data.value.toLocaleString(),
977
+ data.unit && /* @__PURE__ */ jsx7("span", { className: "ml-1 text-base text-slate-500", children: data.unit })
978
+ ] }),
979
+ data.operation && /* @__PURE__ */ jsx7("div", { className: "mt-1 text-xs text-slate-500 dark:text-slate-400", children: data.operation })
980
+ ] });
981
+ }
868
982
  function LineChartView({ data, primaryColor, isStreaming }) {
869
983
  if (isStreaming) return /* @__PURE__ */ jsx7(ChartSkeleton, { type: "bar" });
870
984
  if (!Array.isArray(data) || data.length === 0) {
@@ -998,7 +1112,7 @@ function CarouselView({
998
1112
  ) });
999
1113
  }
1000
1114
  function TextView({ data }) {
1001
- const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
1115
+ const content = stripLeakedAnswerWrappers((data == null ? void 0 : data.content) || String(data != null ? data : ""));
1002
1116
  return /* @__PURE__ */ jsx7("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm", children: /* @__PURE__ */ jsx7("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed", children: content }) });
1003
1117
  }
1004
1118
 
@@ -1447,6 +1561,14 @@ var FIELD_SYNONYMS = {
1447
1561
  "in stock",
1448
1562
  "status"
1449
1563
  ],
1564
+ category: [
1565
+ "product_category",
1566
+ "product category",
1567
+ "category_name",
1568
+ "category name",
1569
+ "department",
1570
+ "collection"
1571
+ ],
1450
1572
  description: ["summary", "content", "body", "text", "info", "details"],
1451
1573
  link: ["url", "href", "product_url", "page_url", "link"]
1452
1574
  };
@@ -1654,11 +1776,12 @@ function extractProductsFromSources(sources, isUser) {
1654
1776
  var _a;
1655
1777
  const m = (_a = s.metadata) != null ? _a : {};
1656
1778
  const keys = Object.keys(m).map((k) => k.toLowerCase());
1657
- const hasProductKey = keys.some(
1658
- (k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
1779
+ const hasStrongProductKey = keys.some(
1780
+ (k) => ["price", "image", "img", "thumbnail", "images", "product", "sku", "cost"].includes(k)
1659
1781
  );
1782
+ const hasProductIdentity = keys.some((k) => ["brand", "model"].includes(k)) && keys.some((k) => ["name", "title", "product_name", "product"].includes(k));
1660
1783
  const hasPricePattern = /\$\s*\d+/.test(s.content);
1661
- return hasProductKey || hasPricePattern || m.type === "product";
1784
+ return hasStrongProductKey || hasProductIdentity || hasPricePattern || m.type === "product";
1662
1785
  }).map((s) => {
1663
1786
  var _a, _b;
1664
1787
  const m = (_a = s.metadata) != null ? _a : {};
@@ -1845,6 +1968,7 @@ function resolveStructuredRows(config) {
1845
1968
  }
1846
1969
  function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
1847
1970
  var _a;
1971
+ console.log("rawContent", rawContent);
1848
1972
  const result = React7.useMemo(() => {
1849
1973
  try {
1850
1974
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
@@ -1979,12 +2103,11 @@ function createMarkdownComponents({
1979
2103
  viewportSize
1980
2104
  }) {
1981
2105
  return {
1982
- p: (_a) => {
2106
+ // p: ({ ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
2107
+ // <p className="whitespace-pre-line" {...props} />
2108
+ // ),
2109
+ table: (_a) => {
1983
2110
  var props = __objRest(_a, []);
1984
- return /* @__PURE__ */ jsx11("p", __spreadValues({ className: "whitespace-pre-line" }, props));
1985
- },
1986
- table: (_b) => {
1987
- var props = __objRest(_b, []);
1988
2111
  if (isStreaming) {
1989
2112
  return /* @__PURE__ */ jsxs10("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none", children: [
1990
2113
  /* @__PURE__ */ jsx11("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }),
@@ -1998,8 +2121,8 @@ function createMarkdownComponents({
1998
2121
  }, props)
1999
2122
  ) }) });
2000
2123
  },
2001
- thead: (_c) => {
2002
- var props = __objRest(_c, []);
2124
+ thead: (_b) => {
2125
+ var props = __objRest(_b, []);
2003
2126
  return /* @__PURE__ */ jsx11(
2004
2127
  "thead",
2005
2128
  __spreadValues({
@@ -2007,12 +2130,12 @@ function createMarkdownComponents({
2007
2130
  }, props)
2008
2131
  );
2009
2132
  },
2010
- tbody: (_d) => {
2011
- var props = __objRest(_d, []);
2133
+ tbody: (_c) => {
2134
+ var props = __objRest(_c, []);
2012
2135
  return /* @__PURE__ */ jsx11("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
2013
2136
  },
2014
- tr: (_e) => {
2015
- var props = __objRest(_e, []);
2137
+ tr: (_d) => {
2138
+ var props = __objRest(_d, []);
2016
2139
  return /* @__PURE__ */ jsx11(
2017
2140
  "tr",
2018
2141
  __spreadValues({
@@ -2020,8 +2143,8 @@ function createMarkdownComponents({
2020
2143
  }, props)
2021
2144
  );
2022
2145
  },
2023
- th: (_f) => {
2024
- var _g = _f, { children } = _g, props = __objRest(_g, ["children"]);
2146
+ th: (_e) => {
2147
+ var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
2025
2148
  return /* @__PURE__ */ jsx11(
2026
2149
  "th",
2027
2150
  __spreadProps(__spreadValues({
@@ -2031,8 +2154,8 @@ function createMarkdownComponents({
2031
2154
  })
2032
2155
  );
2033
2156
  },
2034
- td: (_h) => {
2035
- var _i = _h, { children } = _i, props = __objRest(_i, ["children"]);
2157
+ td: (_g) => {
2158
+ var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
2036
2159
  return /* @__PURE__ */ jsx11(
2037
2160
  "td",
2038
2161
  __spreadProps(__spreadValues({
@@ -2042,12 +2165,12 @@ function createMarkdownComponents({
2042
2165
  })
2043
2166
  );
2044
2167
  },
2045
- code(_j) {
2046
- var _k = _j, {
2168
+ code(_i) {
2169
+ var _j = _i, {
2047
2170
  inline,
2048
2171
  className,
2049
2172
  children
2050
- } = _k, props = __objRest(_k, [
2173
+ } = _j, props = __objRest(_j, [
2051
2174
  "inline",
2052
2175
  "className",
2053
2176
  "children"
@@ -2097,6 +2220,16 @@ function normaliseChild(children) {
2097
2220
 
2098
2221
  // src/components/MessageBubble.tsx
2099
2222
  import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2223
+ function normalizePlusSeparatedLists(raw) {
2224
+ return raw.split("\n").map((line) => {
2225
+ const productListLine = /[—:]\s*\d+\s+\+\s+[A-Za-z]/.test(line) || /\b(products?|categories?|in stock|out of stock)\b/i.test(line);
2226
+ if (!productListLine) return line;
2227
+ return line.replace(/\s+\+\s+(?=[A-Za-z0-9])/g, ", ");
2228
+ }).join("\n");
2229
+ }
2230
+ function stripLeakedAnswerWrappers2(raw) {
2231
+ return raw.replace(/<prose\s+answer(?:\s+in\s+[^>]*)?>\s*([\s\S]*?)\s*<\/prose>/gi, "$1").replace(/<\/?prose(?:\s+answer)?[^>]*>/gi, "").replace(/\n{3,}/g, "\n\n").trim();
2232
+ }
2100
2233
  function MessageBubble({
2101
2234
  message,
2102
2235
  sources,
@@ -2106,6 +2239,7 @@ function MessageBubble({
2106
2239
  onAddToCart,
2107
2240
  viewportSize = "large"
2108
2241
  }) {
2242
+ var _a;
2109
2243
  const isUser = message.role === "user";
2110
2244
  const isCompact = viewportSize === "compact";
2111
2245
  const isMedium = viewportSize === "medium";
@@ -2125,6 +2259,10 @@ function MessageBubble({
2125
2259
  }
2126
2260
  return false;
2127
2261
  }, [message.uiTransformation, structuredContent.payload]);
2262
+ const uiTransformationType = (_a = message.uiTransformation) == null ? void 0 : _a.type;
2263
+ const shouldSuppressProductCarousel = Boolean(
2264
+ uiTransformationType && !["text", "product_carousel", "carousel"].includes(uiTransformationType)
2265
+ );
2128
2266
  const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
2129
2267
  const productsFromSources = React9.useMemo(() => {
2130
2268
  return extractProductsFromSources(sources, isUser);
@@ -2150,6 +2288,14 @@ function MessageBubble({
2150
2288
  }, [productsFromSources, productsFromContent, message.content]);
2151
2289
  const processedMarkdown = React9.useMemo(() => {
2152
2290
  let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
2291
+ raw = raw.replace(/\$\s*(\d+)(?!\.\d)/g, "$1");
2292
+ raw = normalizePlusSeparatedLists(raw);
2293
+ raw = stripLeakedAnswerWrappers2(raw);
2294
+ raw = raw.replace(/\*\*([^*\n]+)\*\*(\s*[—\-–:]\s*)/g, "$1$2");
2295
+ raw = raw.split("\n").filter((line, idx, arr) => {
2296
+ const trimmed = line.trim();
2297
+ return !trimmed || arr.findIndex((l) => l.trim() === trimmed) === idx;
2298
+ }).join("\n");
2153
2299
  const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
2154
2300
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
2155
2301
  if (!isStreaming) {
@@ -2223,11 +2369,11 @@ ${match.trim()}
2223
2369
  }
2224
2370
  ),
2225
2371
  (() => {
2226
- var _a, _b;
2372
+ var _a2, _b;
2227
2373
  if (isUser || structuredContent.payload || !message.uiTransformation) return null;
2228
2374
  const ui = message.uiTransformation;
2229
- const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
2230
- const shouldShow = ui.type === "table" && allProducts.length === 0 || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
2375
+ const textContent = (_b = (_a2 = ui.data) == null ? void 0 : _a2.content) != null ? _b : "";
2376
+ const shouldShow = ui.type === "table" || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
2231
2377
  if (!shouldShow) return null;
2232
2378
  return /* @__PURE__ */ jsx12("div", { className: "w-full mt-3", children: /* @__PURE__ */ jsx12(
2233
2379
  VisualizationRenderer,
@@ -2240,7 +2386,7 @@ ${match.trim()}
2240
2386
  }
2241
2387
  ) });
2242
2388
  })(),
2243
- !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "w-full mt-1", children: /* @__PURE__ */ jsx12(
2389
+ !isUser && !hasRichUI && !shouldSuppressProductCarousel && allProducts.length > 0 && /* @__PURE__ */ jsx12("div", { className: "w-full mt-1", children: /* @__PURE__ */ jsx12(
2244
2390
  ProductCarousel,
2245
2391
  {
2246
2392
  products: allProducts,
@@ -2394,6 +2540,23 @@ function useRagChat(projectId, options = {}) {
2394
2540
  let uiTransformation = null;
2395
2541
  let trace;
2396
2542
  let buffer = "";
2543
+ let pendingFlush = false;
2544
+ const pendingContentRef = { current: "" };
2545
+ const flushTextUpdate = (msgId) => {
2546
+ pendingFlush = false;
2547
+ const snapshot = pendingContentRef.current;
2548
+ setMessages(
2549
+ (prev) => prev.map(
2550
+ (msg) => msg.id === msgId ? __spreadProps(__spreadValues({}, msg), { content: snapshot }) : msg
2551
+ )
2552
+ );
2553
+ };
2554
+ const scheduleFlush = (msgId) => {
2555
+ if (!pendingFlush) {
2556
+ pendingFlush = true;
2557
+ requestAnimationFrame(() => flushTextUpdate(msgId));
2558
+ }
2559
+ };
2397
2560
  const assistantMessageId = `assistant_${Date.now()}`;
2398
2561
  setMessages((prev) => [
2399
2562
  ...prev,
@@ -2412,28 +2575,37 @@ function useRagChat(projectId, options = {}) {
2412
2575
  if (lastBoundary === -1) continue;
2413
2576
  const complete = buffer.slice(0, lastBoundary + 2);
2414
2577
  buffer = buffer.slice(lastBoundary + 2);
2578
+ let hasNonTextFrame = false;
2415
2579
  for (const frame of parseSseChunk(complete)) {
2416
2580
  if (frame.type === "text" && frame.text) {
2417
2581
  assistantContent += frame.text;
2582
+ pendingContentRef.current = assistantContent;
2583
+ scheduleFlush(assistantMessageId);
2418
2584
  } else if (frame.type === "metadata") {
2419
2585
  sources = (_a = frame.sources) != null ? _a : [];
2586
+ hasNonTextFrame = true;
2420
2587
  } else if (frame.type === "ui_transformation") {
2421
2588
  uiTransformation = frame.data;
2589
+ hasNonTextFrame = true;
2422
2590
  } else if (frame.type === "observability") {
2423
2591
  trace = frame.data;
2592
+ hasNonTextFrame = true;
2424
2593
  } else if (frame.type === "error") {
2425
2594
  setError(frame.error || "Stream error");
2426
2595
  }
2427
2596
  }
2428
- setMessages(
2429
- (prev) => prev.map(
2430
- (msg) => msg.id === assistantMessageId ? __spreadProps(__spreadValues({}, msg), {
2431
- content: assistantContent,
2432
- sources: sources.length > 0 ? sources : msg.sources,
2433
- uiTransformation: uiTransformation || msg.uiTransformation
2434
- }) : msg
2435
- )
2436
- );
2597
+ if (hasNonTextFrame) {
2598
+ pendingFlush = false;
2599
+ setMessages(
2600
+ (prev) => prev.map(
2601
+ (msg) => msg.id === assistantMessageId ? __spreadProps(__spreadValues({}, msg), {
2602
+ content: assistantContent,
2603
+ sources: sources.length > 0 ? sources : msg.sources,
2604
+ uiTransformation: uiTransformation || msg.uiTransformation
2605
+ }) : msg
2606
+ )
2607
+ );
2608
+ }
2437
2609
  }
2438
2610
  if (buffer.trim()) {
2439
2611
  for (const frame of parseSseChunk(buffer)) {
package/dist/server.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-CbUtvWAW.mjs';
1
+ import { n as VectorDBConfig, L as LLMConfig, e as EmbeddingConfig, k as RagConfig, I as ILLMProvider, g as IngestDocument, C as ChatMessage, d as ChatResponse, p as RetrievalResult, m as UpsertDocument, V as VectorMatch, G as GraphDBConfig, q as GraphNode, r as Edge, s as GraphSearchResult, o as VectorDBProvider, h as LLMProvider, f as EmbeddingProvider, j as RAGConfig, U as UIConfig, c as ChatOptions, E as EmbedOptions } from './ILLMProvider-BQyKZLnd.mjs';
2
2
  export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-Dh9TvmGG.mjs';
3
- import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-c_y_5qdw.mjs';
4
- export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-c_y_5qdw.mjs';
3
+ import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-CDftK3qs.mjs';
4
+ export { C as ConfigValidator, V as ValidationError, b as VectorPlugin, c as createChatHandler, d as createHealthHandler, e as createIngestHandler, f as createStreamHandler, g as createUploadHandler, s as sseErrorFrame, h as sseFrame, i as sseMetaFrame, j as sseTextFrame } from './index-CDftK3qs.mjs';
5
5
  import 'next/server';
6
6
 
7
7
  /**
@@ -113,6 +113,7 @@ declare class Pipeline {
113
113
  private graphDB?;
114
114
  private llmProvider;
115
115
  private embeddingProvider;
116
+ private llmRouter;
116
117
  private chunker;
117
118
  private llamaIngestor?;
118
119
  private entityExtractor?;
@@ -150,6 +151,12 @@ declare class Pipeline {
150
151
  /**
151
152
  * High-performance streaming RAG flow.
152
153
  * Yields text chunks first, then the retrieval metadata + observability trace at the end.
154
+ *
155
+ * Latency optimizations:
156
+ * - Strategy classification runs in parallel with query embedding (saves ~400ms)
157
+ * - Hallucination scoring is fire-and-forget (doesn't block metadata yield)
158
+ * - UITransformation is computed after text streaming and emitted with metadata
159
+ * - SchemaMapper.train runs while answer generation streams
153
160
  */
154
161
  askStream(question: string, history?: ChatMessage[], namespace?: string): AsyncIterable<string | ChatResponse>;
155
162
  /**
@@ -157,6 +164,14 @@ declare class Pipeline {
157
164
  * Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
158
165
  */
159
166
  private generateUiTransformation;
167
+ private applyStructuredFilters;
168
+ private resolveNumericPredicateValue;
169
+ private extractNumericValueFromContent;
170
+ private matchesNumericPredicate;
171
+ private normalizeComparableField;
172
+ private fieldSimilarityScore;
173
+ private fieldTokens;
174
+ private toFiniteNumber;
160
175
  retrieve(query: string, options: {
161
176
  namespace?: string;
162
177
  topK?: number;
@@ -811,8 +826,8 @@ declare class RedisProvider extends BaseVectorProvider {
811
826
  delete(id: string, namespace?: string): Promise<void>;
812
827
  deleteNamespace(namespace: string): Promise<void>;
813
828
  /**
814
- * Redis is TCP-based and has no HTTP health endpoint.
815
- * Returns true; actual connectivity is validated on the first operation.
829
+ * Check reachability via a PING command.
830
+ * Returns false on connection failure so health checks surface real problems.
816
831
  */
817
832
  ping(): Promise<boolean>;
818
833
  disconnect(): Promise<void>;
@@ -838,6 +853,9 @@ declare class WeaviateProvider extends BaseVectorProvider {
838
853
  deleteNamespace(namespace: string): Promise<void>;
839
854
  ping(): Promise<boolean>;
840
855
  disconnect(): Promise<void>;
856
+ private extractPrimitiveMetadata;
857
+ private buildWhereFilter;
858
+ private weaviateOperand;
841
859
  }
842
860
 
843
861
  /**
@@ -969,8 +987,17 @@ declare class UniversalLLMAdapter implements ILLMProvider {
969
987
  private readonly systemPrompt;
970
988
  private readonly maxTokens;
971
989
  private readonly temperature;
990
+ private readonly baseUrl;
991
+ private readonly apiKey?;
992
+ private readonly resolvedHeaders;
972
993
  constructor(config: LLMConfig | EmbeddingConfig);
973
994
  chat(messages: ChatMessage[], context?: string): Promise<string>;
995
+ /**
996
+ * Streaming chat using native fetch + ReadableStream.
997
+ * Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
998
+ * Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
999
+ */
1000
+ chatStream(messages: ChatMessage[], context?: string): AsyncIterable<string>;
974
1001
  embed(text: string): Promise<number[]>;
975
1002
  batchEmbed(texts: string[]): Promise<number[][]>;
976
1003
  ping(): Promise<boolean>;