@retrivora-ai/rag-engine 1.7.1 → 1.7.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.
package/dist/index.js CHANGED
@@ -405,7 +405,7 @@ function sanitizeJson(raw) {
405
405
  return `: ${result}`;
406
406
  }
407
407
  );
408
- s = s.replace(/(^|[^\:])\/\/[^\n]*/g, "$1");
408
+ s = s.replace(/\/\/[^\n]*/g, "");
409
409
  s = s.replace(/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g, '$1"$2":');
410
410
  s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
411
411
  s = s.replace(/,\s*([}\]])/g, "$1");
@@ -456,7 +456,7 @@ function extractLikelyJsonBlock(raw) {
456
456
  return trimmed.slice(Math.min(...starts));
457
457
  }
458
458
  function looksLikeStructuredPayload(raw) {
459
- return /"?(view|chartType|type|data|items|rows|products|results|columns|xAxisKey)"?\s*:/.test(raw);
459
+ return /"?(view|chartType|type|data|items|rows|products|results)"?\s*:/.test(raw);
460
460
  }
461
461
  function stripMarkdownTables(raw) {
462
462
  return raw.replace(
@@ -535,23 +535,12 @@ function isLikelyUiOnlyMessage(text) {
535
535
  return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
536
536
  }
537
537
  function resolveImage(data) {
538
- const candidates = ["image", "img", "thumbnail", "url", "picture", "link"];
539
- for (const key of candidates) {
538
+ for (const key of ["image", "img", "thumbnail"]) {
540
539
  const v = data[key];
541
- if (typeof v === "string" && v.startsWith("http")) return v;
542
- if (v && typeof v === "object" && !Array.isArray(v)) {
543
- const subVal = v.url || v.link || v.src;
544
- if (typeof subVal === "string" && subVal.startsWith("http")) return subVal;
545
- }
540
+ if (typeof v === "string" && v) return v;
546
541
  }
547
- if (Array.isArray(data.images)) {
548
- for (const item of data.images) {
549
- if (typeof item === "string" && item.startsWith("http")) return item;
550
- if (item && typeof item === "object") {
551
- const url = item.url || item.link || item.src;
552
- if (typeof url === "string" && url.startsWith("http")) return url;
553
- }
554
- }
542
+ if (Array.isArray(data.images) && typeof data.images[0] === "string") {
543
+ return data.images[0];
555
544
  }
556
545
  return void 0;
557
546
  }
@@ -654,13 +643,10 @@ function resolveStructuredRows(config) {
654
643
  if (Array.isArray(config.results) && config.results.length > 0) return config.results;
655
644
  return [];
656
645
  }
657
- function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, viewportSize = "large" }) {
646
+ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
658
647
  var _a;
659
648
  const result = import_react5.default.useMemo(() => {
660
- if (isStreaming) {
661
- const looksLikeCarousel = rawContent.includes('"view": "carousel"') || rawContent.includes('"view":"carousel"') || rawContent.includes('"type": "products"') || rawContent.includes('"type":"products"');
662
- return { loading: true, silent: looksLikeCarousel };
663
- }
649
+ if (isStreaming) return { loading: true };
664
650
  try {
665
651
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
666
652
  const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
@@ -693,7 +679,6 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, view
693
679
  }
694
680
  }, [rawContent, isStreaming]);
695
681
  if ("loading" in result) {
696
- if (result.silent) return null;
697
682
  return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
698
683
  }
699
684
  if ("error" in result) {
@@ -728,7 +713,12 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, view
728
713
  insight
729
714
  ))));
730
715
  case "carousel":
731
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description));
716
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
717
+ var _a2;
718
+ return __spreadProps(__spreadValues({}, item), {
719
+ image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
720
+ });
721
+ }), primaryColor, onAddToCart }));
732
722
  case "table":
733
723
  return /* @__PURE__ */ import_react5.default.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(DataTable, { config: {
734
724
  type: "table",
@@ -756,6 +746,10 @@ function MessageBubble({
756
746
  const isCompact = viewportSize === "compact";
757
747
  const isMedium = viewportSize === "medium";
758
748
  const [showSources, setShowSources] = import_react5.default.useState(false);
749
+ const hasStructuredProductBlock = import_react5.default.useMemo(
750
+ () => /```(?:ui|json|chart)\s*[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products|table)"?/i.test(message.content) || /\{[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products)"?[\s\S]*\}/i.test(message.content) && looksLikeStructuredPayload(message.content),
751
+ [message.content]
752
+ );
759
753
  const structuredContent = import_react5.default.useMemo(
760
754
  () => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
761
755
  [isUser, message.content]
@@ -828,41 +822,34 @@ function MessageBubble({
828
822
  return { productsFromContent: products, cleanContent: content.trim() };
829
823
  }, [message.content, isUser, structuredContent]);
830
824
  const allProducts = import_react5.default.useMemo(() => {
825
+ if (productsFromContent.length > 0) return productsFromContent;
831
826
  const seen = /* @__PURE__ */ new Set();
832
- const merged = [];
833
- for (const p of productsFromContent) {
834
- const id = String(p.id || p.name);
835
- if (!seen.has(id)) {
836
- seen.add(id);
837
- merged.push(p);
838
- }
839
- }
840
827
  const contentLower = message.content.toLowerCase();
841
- for (const p of productsFromSources) {
842
- const id = String(p.id || p.name);
843
- if (seen.has(id)) continue;
828
+ return productsFromSources.filter((p) => {
829
+ var _a;
830
+ const id = String((_a = p.id) != null ? _a : p.name);
831
+ if (seen.has(id)) return false;
844
832
  const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
845
833
  if (mentioned) {
846
834
  seen.add(id);
847
- merged.push(p);
835
+ return true;
848
836
  }
849
- }
850
- return merged;
837
+ return false;
838
+ });
851
839
  }, [productsFromSources, productsFromContent, message.content]);
852
840
  const processedMarkdown = import_react5.default.useMemo(() => {
853
841
  let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
854
842
  const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
855
843
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
856
- if (!isStreaming && !hasStructuredUiBlock) {
857
- raw = raw.replace(/(?:^|\n)\s*(\{[\s\S]+?\})(?:\s*\n|$)/g, (match, body) => {
844
+ if (!isStreaming) {
845
+ raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
858
846
  if (match.includes("```")) return match;
859
- const trimmedBody = body.trim();
860
- if (!looksLikeStructuredPayload(trimmedBody)) return match;
861
- const type = trimmedBody.includes('"view"') || trimmedBody.includes('"chartType"') || trimmedBody.includes('"type"') || trimmedBody.includes('"xAxisKey"') ? "ui" : "json";
847
+ if (!looksLikeStructuredPayload(match)) return match;
848
+ const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
862
849
  return `
863
850
 
864
851
  \`\`\`${type}
865
- ${trimmedBody}
852
+ ${match.trim()}
866
853
  \`\`\`
867
854
 
868
855
  `;
@@ -962,6 +949,7 @@ ${match.trim()}
962
949
  primaryColor,
963
950
  accentColor,
964
951
  isStreaming,
952
+ onAddToCart,
965
953
  viewportSize
966
954
  }
967
955
  );
@@ -976,6 +964,7 @@ ${match.trim()}
976
964
  primaryColor,
977
965
  accentColor,
978
966
  isStreaming,
967
+ onAddToCart,
979
968
  viewportSize
980
969
  }
981
970
  );
@@ -991,6 +980,7 @@ ${match.trim()}
991
980
  primaryColor,
992
981
  accentColor,
993
982
  isStreaming,
983
+ onAddToCart,
994
984
  viewportSize
995
985
  }
996
986
  );
@@ -1002,7 +992,7 @@ ${match.trim()}
1002
992
  return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
1003
993
  }
1004
994
  }),
1005
- [primaryColor, accentColor, isStreaming, viewportSize]
995
+ [primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
1006
996
  );
1007
997
  return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
1008
998
  "div",
@@ -1024,10 +1014,11 @@ ${match.trim()}
1024
1014
  primaryColor,
1025
1015
  accentColor,
1026
1016
  isStreaming,
1017
+ onAddToCart,
1027
1018
  viewportSize
1028
1019
  }
1029
1020
  ), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
1030
- ), !isUser && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
1021
+ ), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
1031
1022
  ProductCarousel,
1032
1023
  {
1033
1024
  products: allProducts,
package/dist/index.mjs CHANGED
@@ -368,7 +368,7 @@ function sanitizeJson(raw) {
368
368
  return `: ${result}`;
369
369
  }
370
370
  );
371
- s = s.replace(/(^|[^\:])\/\/[^\n]*/g, "$1");
371
+ s = s.replace(/\/\/[^\n]*/g, "");
372
372
  s = s.replace(/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g, '$1"$2":');
373
373
  s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
374
374
  s = s.replace(/,\s*([}\]])/g, "$1");
@@ -419,7 +419,7 @@ function extractLikelyJsonBlock(raw) {
419
419
  return trimmed.slice(Math.min(...starts));
420
420
  }
421
421
  function looksLikeStructuredPayload(raw) {
422
- return /"?(view|chartType|type|data|items|rows|products|results|columns|xAxisKey)"?\s*:/.test(raw);
422
+ return /"?(view|chartType|type|data|items|rows|products|results)"?\s*:/.test(raw);
423
423
  }
424
424
  function stripMarkdownTables(raw) {
425
425
  return raw.replace(
@@ -498,23 +498,12 @@ function isLikelyUiOnlyMessage(text) {
498
498
  return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
499
499
  }
500
500
  function resolveImage(data) {
501
- const candidates = ["image", "img", "thumbnail", "url", "picture", "link"];
502
- for (const key of candidates) {
501
+ for (const key of ["image", "img", "thumbnail"]) {
503
502
  const v = data[key];
504
- if (typeof v === "string" && v.startsWith("http")) return v;
505
- if (v && typeof v === "object" && !Array.isArray(v)) {
506
- const subVal = v.url || v.link || v.src;
507
- if (typeof subVal === "string" && subVal.startsWith("http")) return subVal;
508
- }
503
+ if (typeof v === "string" && v) return v;
509
504
  }
510
- if (Array.isArray(data.images)) {
511
- for (const item of data.images) {
512
- if (typeof item === "string" && item.startsWith("http")) return item;
513
- if (item && typeof item === "object") {
514
- const url = item.url || item.link || item.src;
515
- if (typeof url === "string" && url.startsWith("http")) return url;
516
- }
517
- }
505
+ if (Array.isArray(data.images) && typeof data.images[0] === "string") {
506
+ return data.images[0];
518
507
  }
519
508
  return void 0;
520
509
  }
@@ -617,13 +606,10 @@ function resolveStructuredRows(config) {
617
606
  if (Array.isArray(config.results) && config.results.length > 0) return config.results;
618
607
  return [];
619
608
  }
620
- function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, viewportSize = "large" }) {
609
+ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
621
610
  var _a;
622
611
  const result = React5.useMemo(() => {
623
- if (isStreaming) {
624
- const looksLikeCarousel = rawContent.includes('"view": "carousel"') || rawContent.includes('"view":"carousel"') || rawContent.includes('"type": "products"') || rawContent.includes('"type":"products"');
625
- return { loading: true, silent: looksLikeCarousel };
626
- }
612
+ if (isStreaming) return { loading: true };
627
613
  try {
628
614
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
629
615
  const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
@@ -656,7 +642,6 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, view
656
642
  }
657
643
  }, [rawContent, isStreaming]);
658
644
  if ("loading" in result) {
659
- if (result.silent) return null;
660
645
  return /* @__PURE__ */ React5.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ React5.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ React5.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
661
646
  }
662
647
  if ("error" in result) {
@@ -691,7 +676,12 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, view
691
676
  insight
692
677
  ))));
693
678
  case "carousel":
694
- return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description));
679
+ return /* @__PURE__ */ React5.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(ProductCarousel, { products: config.data.map((item) => {
680
+ var _a2;
681
+ return __spreadProps(__spreadValues({}, item), {
682
+ image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
683
+ });
684
+ }), primaryColor, onAddToCart }));
695
685
  case "table":
696
686
  return /* @__PURE__ */ React5.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ React5.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ React5.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ React5.createElement(DataTable, { config: {
697
687
  type: "table",
@@ -719,6 +709,10 @@ function MessageBubble({
719
709
  const isCompact = viewportSize === "compact";
720
710
  const isMedium = viewportSize === "medium";
721
711
  const [showSources, setShowSources] = React5.useState(false);
712
+ const hasStructuredProductBlock = React5.useMemo(
713
+ () => /```(?:ui|json|chart)\s*[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products|table)"?/i.test(message.content) || /\{[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products)"?[\s\S]*\}/i.test(message.content) && looksLikeStructuredPayload(message.content),
714
+ [message.content]
715
+ );
722
716
  const structuredContent = React5.useMemo(
723
717
  () => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
724
718
  [isUser, message.content]
@@ -791,41 +785,34 @@ function MessageBubble({
791
785
  return { productsFromContent: products, cleanContent: content.trim() };
792
786
  }, [message.content, isUser, structuredContent]);
793
787
  const allProducts = React5.useMemo(() => {
788
+ if (productsFromContent.length > 0) return productsFromContent;
794
789
  const seen = /* @__PURE__ */ new Set();
795
- const merged = [];
796
- for (const p of productsFromContent) {
797
- const id = String(p.id || p.name);
798
- if (!seen.has(id)) {
799
- seen.add(id);
800
- merged.push(p);
801
- }
802
- }
803
790
  const contentLower = message.content.toLowerCase();
804
- for (const p of productsFromSources) {
805
- const id = String(p.id || p.name);
806
- if (seen.has(id)) continue;
791
+ return productsFromSources.filter((p) => {
792
+ var _a;
793
+ const id = String((_a = p.id) != null ? _a : p.name);
794
+ if (seen.has(id)) return false;
807
795
  const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
808
796
  if (mentioned) {
809
797
  seen.add(id);
810
- merged.push(p);
798
+ return true;
811
799
  }
812
- }
813
- return merged;
800
+ return false;
801
+ });
814
802
  }, [productsFromSources, productsFromContent, message.content]);
815
803
  const processedMarkdown = React5.useMemo(() => {
816
804
  let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
817
805
  const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
818
806
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
819
- if (!isStreaming && !hasStructuredUiBlock) {
820
- raw = raw.replace(/(?:^|\n)\s*(\{[\s\S]+?\})(?:\s*\n|$)/g, (match, body) => {
807
+ if (!isStreaming) {
808
+ raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
821
809
  if (match.includes("```")) return match;
822
- const trimmedBody = body.trim();
823
- if (!looksLikeStructuredPayload(trimmedBody)) return match;
824
- const type = trimmedBody.includes('"view"') || trimmedBody.includes('"chartType"') || trimmedBody.includes('"type"') || trimmedBody.includes('"xAxisKey"') ? "ui" : "json";
810
+ if (!looksLikeStructuredPayload(match)) return match;
811
+ const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
825
812
  return `
826
813
 
827
814
  \`\`\`${type}
828
- ${trimmedBody}
815
+ ${match.trim()}
829
816
  \`\`\`
830
817
 
831
818
  `;
@@ -925,6 +912,7 @@ ${match.trim()}
925
912
  primaryColor,
926
913
  accentColor,
927
914
  isStreaming,
915
+ onAddToCart,
928
916
  viewportSize
929
917
  }
930
918
  );
@@ -939,6 +927,7 @@ ${match.trim()}
939
927
  primaryColor,
940
928
  accentColor,
941
929
  isStreaming,
930
+ onAddToCart,
942
931
  viewportSize
943
932
  }
944
933
  );
@@ -954,6 +943,7 @@ ${match.trim()}
954
943
  primaryColor,
955
944
  accentColor,
956
945
  isStreaming,
946
+ onAddToCart,
957
947
  viewportSize
958
948
  }
959
949
  );
@@ -965,7 +955,7 @@ ${match.trim()}
965
955
  return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
966
956
  }
967
957
  }),
968
- [primaryColor, accentColor, isStreaming, viewportSize]
958
+ [primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
969
959
  );
970
960
  return /* @__PURE__ */ React5.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
971
961
  "div",
@@ -987,10 +977,11 @@ ${match.trim()}
987
977
  primaryColor,
988
978
  accentColor,
989
979
  isStreaming,
980
+ onAddToCart,
990
981
  viewportSize
991
982
  }
992
983
  ), !shouldRenderStructuredOnly && /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
993
- ), !isUser && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
984
+ ), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
994
985
  ProductCarousel,
995
986
  {
996
987
  products: allProducts,
package/dist/server.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { j as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, h as RagConfig, I as IngestDocument, C as ChatMessage, d as ChatResponse, l as RetrievalResult, i as UpsertDocument, V as VectorMatch, G as GraphDBConfig, m as GraphNode, n as Edge, o as GraphSearchResult, k as VectorDBProvider, f as LLMProvider, e as EmbeddingProvider, g as RAGConfig, U as UIConfig, c as ChatOptions } from './index-Cti1u0y1.mjs';
2
2
  import { I as ILLMProvider, E as EmbedOptions } from './DocumentChunker-D1dg5iCi.mjs';
3
3
  export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-D1dg5iCi.mjs';
4
- import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-kUXnRvuI.mjs';
5
- 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-kUXnRvuI.mjs';
4
+ import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-BejNscWZ.mjs';
5
+ 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-BejNscWZ.mjs';
6
6
  import 'next/server';
7
7
 
8
8
  /**
package/dist/server.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { j as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, h as RagConfig, I as IngestDocument, C as ChatMessage, d as ChatResponse, l as RetrievalResult, i as UpsertDocument, V as VectorMatch, G as GraphDBConfig, m as GraphNode, n as Edge, o as GraphSearchResult, k as VectorDBProvider, f as LLMProvider, e as EmbeddingProvider, g as RAGConfig, U as UIConfig, c as ChatOptions } from './index-Cti1u0y1.js';
2
2
  import { I as ILLMProvider, E as EmbedOptions } from './DocumentChunker-BXOUMKoP.js';
3
3
  export { C as Chunk, a as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BXOUMKoP.js';
4
- import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-B67KQ9NN.js';
5
- 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-B67KQ9NN.js';
4
+ import { H as HealthCheckResult, I as IProviderValidator, a as IProviderHealthChecker } from './index-CbkMJvu5.js';
5
+ 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-CbkMJvu5.js';
6
6
  import 'next/server';
7
7
 
8
8
  /**