@retrivora-ai/rag-engine 1.6.2 → 1.6.4
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-5K7EU4KW.mjs → chunk-EE2Z4HNW.mjs} +8 -9
- package/dist/handlers/index.js +8 -9
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.js +12 -4
- package/dist/index.mjs +12 -4
- package/dist/server.js +8 -9
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +22 -11
- package/src/core/Pipeline.ts +8 -9
|
@@ -2263,15 +2263,14 @@ var Pipeline = class {
|
|
|
2263
2263
|
const chartInstruction = `
|
|
2264
2264
|
|
|
2265
2265
|
${CHART_MARKER}
|
|
2266
|
-
### UNIVERSAL UI PROTOCOL
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
-
|
|
2271
|
-
-
|
|
2272
|
-
-
|
|
2273
|
-
|
|
2274
|
-
2. REQUIRED JSON SHAPE
|
|
2266
|
+
### UNIVERSAL UI PROTOCOL (EXPERT MODE):
|
|
2267
|
+
You have high-performance graphical capabilities. For any analytical query or product list, you MUST use the \`\`\`ui\`\`\` block.
|
|
2268
|
+
1. WRAPPING: You MUST wrap the JSON in \`\`\`ui and \`\`\` code markers. NEVER output naked JSON.
|
|
2269
|
+
2. VIEW SELECTION:
|
|
2270
|
+
- "chart": ALWAYS use this for distributions, percentages, or statistics. You MUST aggregate/count the data yourself.
|
|
2271
|
+
- "carousel": Use for browsing product items.
|
|
2272
|
+
- "table": Use ONLY for raw data details if explicitly asked for a "table" or "list".
|
|
2273
|
+
3. SCHEMA:
|
|
2275
2274
|
{
|
|
2276
2275
|
"view": "chart" | "carousel" | "table",
|
|
2277
2276
|
"title": "Short heading",
|
package/dist/handlers/index.js
CHANGED
|
@@ -3826,15 +3826,14 @@ var Pipeline = class {
|
|
|
3826
3826
|
const chartInstruction = `
|
|
3827
3827
|
|
|
3828
3828
|
${CHART_MARKER}
|
|
3829
|
-
### UNIVERSAL UI PROTOCOL
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
-
|
|
3834
|
-
-
|
|
3835
|
-
-
|
|
3836
|
-
|
|
3837
|
-
2. REQUIRED JSON SHAPE
|
|
3829
|
+
### UNIVERSAL UI PROTOCOL (EXPERT MODE):
|
|
3830
|
+
You have high-performance graphical capabilities. For any analytical query or product list, you MUST use the \`\`\`ui\`\`\` block.
|
|
3831
|
+
1. WRAPPING: You MUST wrap the JSON in \`\`\`ui and \`\`\` code markers. NEVER output naked JSON.
|
|
3832
|
+
2. VIEW SELECTION:
|
|
3833
|
+
- "chart": ALWAYS use this for distributions, percentages, or statistics. You MUST aggregate/count the data yourself.
|
|
3834
|
+
- "carousel": Use for browsing product items.
|
|
3835
|
+
- "table": Use ONLY for raw data details if explicitly asked for a "table" or "list".
|
|
3836
|
+
3. SCHEMA:
|
|
3838
3837
|
{
|
|
3839
3838
|
"view": "chart" | "carousel" | "table",
|
|
3840
3839
|
"title": "Short heading",
|
package/dist/handlers/index.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -530,6 +530,10 @@ function extractStructuredPayload(raw) {
|
|
|
530
530
|
text: stripStructuredUiLabels(raw).replace(/\n{3,}/g, "\n\n").trim()
|
|
531
531
|
};
|
|
532
532
|
}
|
|
533
|
+
function isLikelyUiOnlyMessage(text) {
|
|
534
|
+
const trimmed = text.trim();
|
|
535
|
+
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation)\s*:?\s*$/i.test(trimmed);
|
|
536
|
+
}
|
|
533
537
|
function resolveImage(data) {
|
|
534
538
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
535
539
|
const v = data[key];
|
|
@@ -746,6 +750,7 @@ function MessageBubble({
|
|
|
746
750
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
747
751
|
[isUser, message.content]
|
|
748
752
|
);
|
|
753
|
+
const shouldRenderStructuredOnly = !isUser && Boolean(structuredContent.payload) && isLikelyUiOnlyMessage(structuredContent.text);
|
|
749
754
|
const productsFromSources = import_react5.default.useMemo(() => {
|
|
750
755
|
if (isUser || !sources) return [];
|
|
751
756
|
return sources.filter((s) => {
|
|
@@ -833,10 +838,13 @@ function MessageBubble({
|
|
|
833
838
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
834
839
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
835
840
|
if (!isStreaming) {
|
|
836
|
-
raw = raw.replace(/(
|
|
837
|
-
if (match.includes("```")) return match;
|
|
841
|
+
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
838
842
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
839
|
-
const
|
|
843
|
+
const index = raw.indexOf(match);
|
|
844
|
+
const prefix = raw.substring(0, index);
|
|
845
|
+
const openBlocks = (prefix.match(/```/g) || []).length;
|
|
846
|
+
if (openBlocks % 2 !== 0) return match;
|
|
847
|
+
const type = match.includes('"view"') || match.includes('"chartType"') ? "ui" : "json";
|
|
840
848
|
return `
|
|
841
849
|
|
|
842
850
|
\`\`\`${type}
|
|
@@ -1008,7 +1016,7 @@ ${match.trim()}
|
|
|
1008
1016
|
onAddToCart,
|
|
1009
1017
|
viewportSize
|
|
1010
1018
|
}
|
|
1011
|
-
), /* @__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" }))
|
|
1019
|
+
), !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" }))
|
|
1012
1020
|
), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
1013
1021
|
ProductCarousel,
|
|
1014
1022
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -493,6 +493,10 @@ function extractStructuredPayload(raw) {
|
|
|
493
493
|
text: stripStructuredUiLabels(raw).replace(/\n{3,}/g, "\n\n").trim()
|
|
494
494
|
};
|
|
495
495
|
}
|
|
496
|
+
function isLikelyUiOnlyMessage(text) {
|
|
497
|
+
const trimmed = text.trim();
|
|
498
|
+
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation)\s*:?\s*$/i.test(trimmed);
|
|
499
|
+
}
|
|
496
500
|
function resolveImage(data) {
|
|
497
501
|
for (const key of ["image", "img", "thumbnail"]) {
|
|
498
502
|
const v = data[key];
|
|
@@ -709,6 +713,7 @@ function MessageBubble({
|
|
|
709
713
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
710
714
|
[isUser, message.content]
|
|
711
715
|
);
|
|
716
|
+
const shouldRenderStructuredOnly = !isUser && Boolean(structuredContent.payload) && isLikelyUiOnlyMessage(structuredContent.text);
|
|
712
717
|
const productsFromSources = React5.useMemo(() => {
|
|
713
718
|
if (isUser || !sources) return [];
|
|
714
719
|
return sources.filter((s) => {
|
|
@@ -796,10 +801,13 @@ function MessageBubble({
|
|
|
796
801
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
797
802
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
798
803
|
if (!isStreaming) {
|
|
799
|
-
raw = raw.replace(/(
|
|
800
|
-
if (match.includes("```")) return match;
|
|
804
|
+
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
801
805
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
802
|
-
const
|
|
806
|
+
const index = raw.indexOf(match);
|
|
807
|
+
const prefix = raw.substring(0, index);
|
|
808
|
+
const openBlocks = (prefix.match(/```/g) || []).length;
|
|
809
|
+
if (openBlocks % 2 !== 0) return match;
|
|
810
|
+
const type = match.includes('"view"') || match.includes('"chartType"') ? "ui" : "json";
|
|
803
811
|
return `
|
|
804
812
|
|
|
805
813
|
\`\`\`${type}
|
|
@@ -971,7 +979,7 @@ ${match.trim()}
|
|
|
971
979
|
onAddToCart,
|
|
972
980
|
viewportSize
|
|
973
981
|
}
|
|
974
|
-
), /* @__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" }))
|
|
982
|
+
), !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" }))
|
|
975
983
|
), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
|
|
976
984
|
ProductCarousel,
|
|
977
985
|
{
|
package/dist/server.js
CHANGED
|
@@ -3917,15 +3917,14 @@ var Pipeline = class {
|
|
|
3917
3917
|
const chartInstruction = `
|
|
3918
3918
|
|
|
3919
3919
|
${CHART_MARKER}
|
|
3920
|
-
### UNIVERSAL UI PROTOCOL
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
-
|
|
3925
|
-
-
|
|
3926
|
-
-
|
|
3927
|
-
|
|
3928
|
-
2. REQUIRED JSON SHAPE
|
|
3920
|
+
### UNIVERSAL UI PROTOCOL (EXPERT MODE):
|
|
3921
|
+
You have high-performance graphical capabilities. For any analytical query or product list, you MUST use the \`\`\`ui\`\`\` block.
|
|
3922
|
+
1. WRAPPING: You MUST wrap the JSON in \`\`\`ui and \`\`\` code markers. NEVER output naked JSON.
|
|
3923
|
+
2. VIEW SELECTION:
|
|
3924
|
+
- "chart": ALWAYS use this for distributions, percentages, or statistics. You MUST aggregate/count the data yourself.
|
|
3925
|
+
- "carousel": Use for browsing product items.
|
|
3926
|
+
- "table": Use ONLY for raw data details if explicitly asked for a "table" or "list".
|
|
3927
|
+
3. SCHEMA:
|
|
3929
3928
|
{
|
|
3930
3929
|
"view": "chart" | "carousel" | "table",
|
|
3931
3930
|
"title": "Short heading",
|
package/dist/server.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.4",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -193,6 +193,11 @@ function extractStructuredPayload(raw: string): { payload: string | null; text:
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
function isLikelyUiOnlyMessage(text: string): boolean {
|
|
197
|
+
const trimmed = text.trim();
|
|
198
|
+
return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation)\s*:?\s*$/i.test(trimmed);
|
|
199
|
+
}
|
|
200
|
+
|
|
196
201
|
// ─── Tiny helpers ─────────────────────────────────────────────────────────────
|
|
197
202
|
|
|
198
203
|
function resolveImage(data: Record<string, unknown>): string | undefined {
|
|
@@ -584,6 +589,7 @@ export function MessageBubble({
|
|
|
584
589
|
() => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
|
|
585
590
|
[isUser, message.content],
|
|
586
591
|
);
|
|
592
|
+
const shouldRenderStructuredOnly = !isUser && Boolean(structuredContent.payload) && isLikelyUiOnlyMessage(structuredContent.text);
|
|
587
593
|
|
|
588
594
|
// ── Products from sources ──────────────────────────────────────────────────
|
|
589
595
|
const productsFromSources = React.useMemo<Product[]>(() => {
|
|
@@ -692,16 +698,19 @@ export function MessageBubble({
|
|
|
692
698
|
.replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, '$1\n'); // Remove blank lines between rows
|
|
693
699
|
|
|
694
700
|
// 2. HEALING: Detect naked JSON charts/products and wrap them if markers are missing
|
|
695
|
-
// This handles models (like Llama 3.2) that often omit the ```
|
|
701
|
+
// This handles models (like Llama 3.2) that often omit the ```ui markers.
|
|
696
702
|
if (!isStreaming) {
|
|
697
|
-
//
|
|
698
|
-
raw = raw.replace(/(
|
|
699
|
-
// Only wrap if not already in a code block
|
|
700
|
-
if (match.includes('```')) return match;
|
|
703
|
+
// Find potential JSON objects that are not already wrapped in code blocks
|
|
704
|
+
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
701
705
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
706
|
+
|
|
707
|
+
// Final check: is it already inside a code block? (heuristic check)
|
|
708
|
+
const index = raw.indexOf(match);
|
|
709
|
+
const prefix = raw.substring(0, index);
|
|
710
|
+
const openBlocks = (prefix.match(/```/g) || []).length;
|
|
711
|
+
if (openBlocks % 2 !== 0) return match;
|
|
712
|
+
|
|
713
|
+
const type = match.includes('"view"') || match.includes('"chartType"') ? 'ui' : 'json';
|
|
705
714
|
return `\n\n\`\`\`${type}\n${match.trim()}\n\`\`\`\n\n`;
|
|
706
715
|
});
|
|
707
716
|
}
|
|
@@ -903,9 +912,11 @@ export function MessageBubble({
|
|
|
903
912
|
/>
|
|
904
913
|
)}
|
|
905
914
|
|
|
906
|
-
|
|
907
|
-
{
|
|
908
|
-
|
|
915
|
+
{!shouldRenderStructuredOnly && (
|
|
916
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
|
917
|
+
{processedMarkdown}
|
|
918
|
+
</ReactMarkdown>
|
|
919
|
+
)}
|
|
909
920
|
|
|
910
921
|
{isStreaming && message.content && (
|
|
911
922
|
<span className="inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" />
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -103,15 +103,14 @@ export class Pipeline {
|
|
|
103
103
|
// We use a unique marker to ensure this is only injected once but is ALWAYS present.
|
|
104
104
|
const CHART_MARKER = '<!-- UI_PROTOCOL_V5 -->';
|
|
105
105
|
const chartInstruction = `\n\n${CHART_MARKER}
|
|
106
|
-
### UNIVERSAL UI PROTOCOL
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
-
|
|
111
|
-
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
2. REQUIRED JSON SHAPE
|
|
106
|
+
### UNIVERSAL UI PROTOCOL (EXPERT MODE):
|
|
107
|
+
You have high-performance graphical capabilities. For any analytical query or product list, you MUST use the \`\`\`ui\`\`\` block.
|
|
108
|
+
1. WRAPPING: You MUST wrap the JSON in \`\`\`ui and \`\`\` code markers. NEVER output naked JSON.
|
|
109
|
+
2. VIEW SELECTION:
|
|
110
|
+
- "chart": ALWAYS use this for distributions, percentages, or statistics. You MUST aggregate/count the data yourself.
|
|
111
|
+
- "carousel": Use for browsing product items.
|
|
112
|
+
- "table": Use ONLY for raw data details if explicitly asked for a "table" or "list".
|
|
113
|
+
3. SCHEMA:
|
|
115
114
|
{
|
|
116
115
|
"view": "chart" | "carousel" | "table",
|
|
117
116
|
"title": "Short heading",
|