@retrivora-ai/rag-engine 1.7.1 → 1.7.2
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/{chunk-OHXRQTQH.mjs → chunk-M32ZXLTT.mjs} +399 -20
- package/dist/handlers/index.d.mts +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.js +402 -22
- package/dist/handlers/index.mjs +5 -3
- package/dist/{index-kUXnRvuI.d.mts → index-BejNscWZ.d.mts} +4 -2
- package/dist/{index-B67KQ9NN.d.ts → index-CbkMJvu5.d.ts} +4 -2
- package/dist/index.js +37 -46
- package/dist/index.mjs +37 -46
- package/dist/server.d.mts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +400 -20
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +54 -80
- package/src/components/VisualizationRenderer.tsx +341 -0
- package/src/core/Pipeline.ts +39 -19
- package/src/handlers/index.ts +21 -3
- package/src/hooks/useUITransform.ts +54 -0
- package/src/utils/UITransformer.ts +535 -0
package/dist/index.js
CHANGED
|
@@ -405,7 +405,7 @@ function sanitizeJson(raw) {
|
|
|
405
405
|
return `: ${result}`;
|
|
406
406
|
}
|
|
407
407
|
);
|
|
408
|
-
s = s.replace(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
|
|
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
|
-
|
|
835
|
+
return true;
|
|
848
836
|
}
|
|
849
|
-
|
|
850
|
-
|
|
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
|
|
857
|
-
raw = raw.replace(/(?:^|\n)\s
|
|
844
|
+
if (!isStreaming) {
|
|
845
|
+
raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
|
|
858
846
|
if (match.includes("```")) return match;
|
|
859
|
-
|
|
860
|
-
|
|
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
|
-
${
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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
|
-
|
|
798
|
+
return true;
|
|
811
799
|
}
|
|
812
|
-
|
|
813
|
-
|
|
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
|
|
820
|
-
raw = raw.replace(/(?:^|\n)\s
|
|
807
|
+
if (!isStreaming) {
|
|
808
|
+
raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
|
|
821
809
|
if (match.includes("```")) return match;
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
${
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
/**
|