@retrivora-ai/rag-engine 1.6.7 → 1.6.8
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-J7BCIPO2.mjs} +29 -28
- package/dist/handlers/index.js +29 -28
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.js +12 -10
- package/dist/index.mjs +12 -10
- package/dist/server.js +29 -28
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +28 -17
- package/src/core/Pipeline.ts +29 -28
|
@@ -2259,7 +2259,7 @@ var Pipeline = class {
|
|
|
2259
2259
|
async initialize() {
|
|
2260
2260
|
var _a, _b;
|
|
2261
2261
|
if (this.initialised) return;
|
|
2262
|
-
const CHART_MARKER = "<!--
|
|
2262
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V6 -->";
|
|
2263
2263
|
const chartInstruction = `
|
|
2264
2264
|
|
|
2265
2265
|
${CHART_MARKER}
|
|
@@ -2267,16 +2267,16 @@ ${CHART_MARKER}
|
|
|
2267
2267
|
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
2268
2268
|
|
|
2269
2269
|
1. VIEW SELECTION
|
|
2270
|
-
- Use "
|
|
2271
|
-
- Use "
|
|
2272
|
-
- Use "table" for
|
|
2270
|
+
- Use "carousel" for browsing specific products, items, or a catalog. This is the DEFAULT for "show me", "what are", or "find me" requests for a specific category (e.g. "beauty").
|
|
2271
|
+
- Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
|
|
2272
|
+
- Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
|
|
2273
2273
|
|
|
2274
2274
|
2. REQUIRED JSON SHAPE
|
|
2275
2275
|
{
|
|
2276
2276
|
"view": "chart" | "carousel" | "table",
|
|
2277
2277
|
"title": "Short heading",
|
|
2278
2278
|
"description": "One sentence describing the view",
|
|
2279
|
-
"chartType": "pie" | "bar" | "line",
|
|
2279
|
+
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
2280
2280
|
"xAxisKey": "label",
|
|
2281
2281
|
"dataKeys": ["value"],
|
|
2282
2282
|
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
@@ -2285,41 +2285,42 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
2285
2285
|
}
|
|
2286
2286
|
|
|
2287
2287
|
3. DATA RULES
|
|
2288
|
-
- Build the UI payload from retrieved context only. Do not invent products
|
|
2289
|
-
-
|
|
2290
|
-
- For
|
|
2291
|
-
-
|
|
2292
|
-
- If stock information exists, preserve it in each row with fields like "inStock", "inStockCount", "outOfStockCount", or "stockStatus".
|
|
2293
|
-
- If the user asks to highlight what is in stock, include those stock-related fields in the chart data and mention the pattern in "insights".
|
|
2294
|
-
- For carousel rows, include product-friendly fields such as id, name, brand, price, image, link, category, stockStatus.
|
|
2295
|
-
- For tables, keep "data" row-oriented and include "columns" only as dynamic field keys/order hints from the fetched data, never as hardcoded UI labels.
|
|
2288
|
+
- Build the UI payload from retrieved context only. Do not invent products or values.
|
|
2289
|
+
- For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
|
|
2290
|
+
- For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
|
|
2291
|
+
- If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
|
|
2296
2292
|
|
|
2297
2293
|
4. FORMAT RULES
|
|
2298
|
-
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
2299
|
-
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
2300
2294
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
2301
|
-
-
|
|
2302
|
-
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
2295
|
+
- Put natural language explanation before or after the block, not inside.
|
|
2303
2296
|
|
|
2304
|
-
5.
|
|
2305
|
-
User: "
|
|
2297
|
+
5. EXAMPLES
|
|
2298
|
+
User: "show me beauty products"
|
|
2299
|
+
Assistant:
|
|
2300
|
+
\`\`\`ui
|
|
2301
|
+
{
|
|
2302
|
+
"view": "carousel",
|
|
2303
|
+
"title": "Beauty Products",
|
|
2304
|
+
"description": "Browse our latest skincare and makeup collection.",
|
|
2305
|
+
"data": [
|
|
2306
|
+
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
|
|
2307
|
+
{ "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
|
|
2308
|
+
]
|
|
2309
|
+
}
|
|
2310
|
+
\`\`\`
|
|
2311
|
+
|
|
2312
|
+
User: "breakdown of products by category"
|
|
2306
2313
|
Assistant:
|
|
2307
2314
|
\`\`\`ui
|
|
2308
2315
|
{
|
|
2309
2316
|
"view": "chart",
|
|
2310
|
-
"title": "
|
|
2311
|
-
"description": "Pie chart showing product count by category with stock signals preserved per slice.",
|
|
2317
|
+
"title": "Category Breakdown",
|
|
2312
2318
|
"chartType": "pie",
|
|
2313
2319
|
"xAxisKey": "label",
|
|
2314
2320
|
"dataKeys": ["value"],
|
|
2315
|
-
"insights": [
|
|
2316
|
-
"Beauty has the highest product count.",
|
|
2317
|
-
"Electronics has the largest number of in-stock products."
|
|
2318
|
-
],
|
|
2319
2321
|
"data": [
|
|
2320
|
-
{ "label": "Beauty", "value":
|
|
2321
|
-
{ "label": "
|
|
2322
|
-
{ "label": "Home", "value": 5, "inStockCount": 2, "outOfStockCount": 3 }
|
|
2322
|
+
{ "label": "Beauty", "value": 15 },
|
|
2323
|
+
{ "label": "Fragrances", "value": 8 }
|
|
2323
2324
|
]
|
|
2324
2325
|
}
|
|
2325
2326
|
\`\`\``;
|
package/dist/handlers/index.js
CHANGED
|
@@ -3822,7 +3822,7 @@ var Pipeline = class {
|
|
|
3822
3822
|
async initialize() {
|
|
3823
3823
|
var _a, _b;
|
|
3824
3824
|
if (this.initialised) return;
|
|
3825
|
-
const CHART_MARKER = "<!--
|
|
3825
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V6 -->";
|
|
3826
3826
|
const chartInstruction = `
|
|
3827
3827
|
|
|
3828
3828
|
${CHART_MARKER}
|
|
@@ -3830,16 +3830,16 @@ ${CHART_MARKER}
|
|
|
3830
3830
|
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
3831
3831
|
|
|
3832
3832
|
1. VIEW SELECTION
|
|
3833
|
-
- Use "
|
|
3834
|
-
- Use "
|
|
3835
|
-
- Use "table" for
|
|
3833
|
+
- Use "carousel" for browsing specific products, items, or a catalog. This is the DEFAULT for "show me", "what are", or "find me" requests for a specific category (e.g. "beauty").
|
|
3834
|
+
- Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
|
|
3835
|
+
- Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
|
|
3836
3836
|
|
|
3837
3837
|
2. REQUIRED JSON SHAPE
|
|
3838
3838
|
{
|
|
3839
3839
|
"view": "chart" | "carousel" | "table",
|
|
3840
3840
|
"title": "Short heading",
|
|
3841
3841
|
"description": "One sentence describing the view",
|
|
3842
|
-
"chartType": "pie" | "bar" | "line",
|
|
3842
|
+
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
3843
3843
|
"xAxisKey": "label",
|
|
3844
3844
|
"dataKeys": ["value"],
|
|
3845
3845
|
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
@@ -3848,41 +3848,42 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
3848
3848
|
}
|
|
3849
3849
|
|
|
3850
3850
|
3. DATA RULES
|
|
3851
|
-
- Build the UI payload from retrieved context only. Do not invent products
|
|
3852
|
-
-
|
|
3853
|
-
- For
|
|
3854
|
-
-
|
|
3855
|
-
- If stock information exists, preserve it in each row with fields like "inStock", "inStockCount", "outOfStockCount", or "stockStatus".
|
|
3856
|
-
- If the user asks to highlight what is in stock, include those stock-related fields in the chart data and mention the pattern in "insights".
|
|
3857
|
-
- For carousel rows, include product-friendly fields such as id, name, brand, price, image, link, category, stockStatus.
|
|
3858
|
-
- For tables, keep "data" row-oriented and include "columns" only as dynamic field keys/order hints from the fetched data, never as hardcoded UI labels.
|
|
3851
|
+
- Build the UI payload from retrieved context only. Do not invent products or values.
|
|
3852
|
+
- For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
|
|
3853
|
+
- For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
|
|
3854
|
+
- If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
|
|
3859
3855
|
|
|
3860
3856
|
4. FORMAT RULES
|
|
3861
|
-
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
3862
|
-
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
3863
3857
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
3864
|
-
-
|
|
3865
|
-
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
3858
|
+
- Put natural language explanation before or after the block, not inside.
|
|
3866
3859
|
|
|
3867
|
-
5.
|
|
3868
|
-
User: "
|
|
3860
|
+
5. EXAMPLES
|
|
3861
|
+
User: "show me beauty products"
|
|
3862
|
+
Assistant:
|
|
3863
|
+
\`\`\`ui
|
|
3864
|
+
{
|
|
3865
|
+
"view": "carousel",
|
|
3866
|
+
"title": "Beauty Products",
|
|
3867
|
+
"description": "Browse our latest skincare and makeup collection.",
|
|
3868
|
+
"data": [
|
|
3869
|
+
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
|
|
3870
|
+
{ "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
|
|
3871
|
+
]
|
|
3872
|
+
}
|
|
3873
|
+
\`\`\`
|
|
3874
|
+
|
|
3875
|
+
User: "breakdown of products by category"
|
|
3869
3876
|
Assistant:
|
|
3870
3877
|
\`\`\`ui
|
|
3871
3878
|
{
|
|
3872
3879
|
"view": "chart",
|
|
3873
|
-
"title": "
|
|
3874
|
-
"description": "Pie chart showing product count by category with stock signals preserved per slice.",
|
|
3880
|
+
"title": "Category Breakdown",
|
|
3875
3881
|
"chartType": "pie",
|
|
3876
3882
|
"xAxisKey": "label",
|
|
3877
3883
|
"dataKeys": ["value"],
|
|
3878
|
-
"insights": [
|
|
3879
|
-
"Beauty has the highest product count.",
|
|
3880
|
-
"Electronics has the largest number of in-stock products."
|
|
3881
|
-
],
|
|
3882
3884
|
"data": [
|
|
3883
|
-
{ "label": "Beauty", "value":
|
|
3884
|
-
{ "label": "
|
|
3885
|
-
{ "label": "Home", "value": 5, "inStockCount": 2, "outOfStockCount": 3 }
|
|
3885
|
+
{ "label": "Beauty", "value": 15 },
|
|
3886
|
+
{ "label": "Fragrances", "value": 8 }
|
|
3886
3887
|
]
|
|
3887
3888
|
}
|
|
3888
3889
|
\`\`\``;
|
package/dist/handlers/index.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -651,23 +651,25 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
651
651
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
652
652
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
653
653
|
const config2 = __spreadValues({}, parsed);
|
|
654
|
+
const resolvedRows = resolveStructuredRows(config2);
|
|
655
|
+
const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
|
|
656
|
+
const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
|
|
657
|
+
if (config2.view === "chart" && hasProductLikeData && !hasAggregationLikeData) {
|
|
658
|
+
config2.view = "carousel";
|
|
659
|
+
} else if (config2.view === "carousel" && hasAggregationLikeData && !hasProductLikeData) {
|
|
660
|
+
config2.view = "chart";
|
|
661
|
+
config2.chartType = config2.chartType || "bar";
|
|
662
|
+
}
|
|
654
663
|
if (!config2.view) {
|
|
655
|
-
|
|
656
|
-
const hasProductLikeData = resolvedRows2.length > 0 && typeof resolvedRows2[0] === "object" && resolvedRows2[0] !== null && ("price" in resolvedRows2[0] || "brand" in resolvedRows2[0] || "image" in resolvedRows2[0]);
|
|
657
|
-
if (config2.type === "products" || Array.isArray(config2.items) || Array.isArray(config2.data) && hasProductLikeData) {
|
|
664
|
+
if (config2.type === "products" || Array.isArray(config2.items) || hasProductLikeData) {
|
|
658
665
|
config2.view = "carousel";
|
|
659
|
-
|
|
660
|
-
} else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
661
|
-
const resolvedChartType = config2.chartType === "pie" || config2.chartType === "bar" || config2.chartType === "line" ? config2.chartType : config2.type === "pie" || config2.type === "bar" || config2.type === "line" ? config2.type : "bar";
|
|
666
|
+
} else if (hasAggregationLikeData || typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
662
667
|
config2.view = "chart";
|
|
663
|
-
config2.chartType =
|
|
664
|
-
config2.data = resolvedRows2;
|
|
668
|
+
config2.chartType = config2.chartType || config2.type || "bar";
|
|
665
669
|
} else {
|
|
666
670
|
config2.view = "table";
|
|
667
|
-
config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
|
|
668
671
|
}
|
|
669
672
|
}
|
|
670
|
-
const resolvedRows = resolveStructuredRows(config2);
|
|
671
673
|
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
672
674
|
data: normalizeTabularRows(resolvedRows, config2.columns)
|
|
673
675
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -614,23 +614,25 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
614
614
|
const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
|
|
615
615
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
616
616
|
const config2 = __spreadValues({}, parsed);
|
|
617
|
+
const resolvedRows = resolveStructuredRows(config2);
|
|
618
|
+
const hasProductLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["price", "brand", "image", "link", "thumbnail"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length >= 4);
|
|
619
|
+
const hasAggregationLikeData = resolvedRows.length > 0 && typeof resolvedRows[0] === "object" && resolvedRows[0] !== null && !Array.isArray(resolvedRows[0]) && (["value", "count", "total", "percentage"].some((key) => key in resolvedRows[0]) || Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some((v) => typeof v === "number"));
|
|
620
|
+
if (config2.view === "chart" && hasProductLikeData && !hasAggregationLikeData) {
|
|
621
|
+
config2.view = "carousel";
|
|
622
|
+
} else if (config2.view === "carousel" && hasAggregationLikeData && !hasProductLikeData) {
|
|
623
|
+
config2.view = "chart";
|
|
624
|
+
config2.chartType = config2.chartType || "bar";
|
|
625
|
+
}
|
|
617
626
|
if (!config2.view) {
|
|
618
|
-
|
|
619
|
-
const hasProductLikeData = resolvedRows2.length > 0 && typeof resolvedRows2[0] === "object" && resolvedRows2[0] !== null && ("price" in resolvedRows2[0] || "brand" in resolvedRows2[0] || "image" in resolvedRows2[0]);
|
|
620
|
-
if (config2.type === "products" || Array.isArray(config2.items) || Array.isArray(config2.data) && hasProductLikeData) {
|
|
627
|
+
if (config2.type === "products" || Array.isArray(config2.items) || hasProductLikeData) {
|
|
621
628
|
config2.view = "carousel";
|
|
622
|
-
|
|
623
|
-
} else if (typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
624
|
-
const resolvedChartType = config2.chartType === "pie" || config2.chartType === "bar" || config2.chartType === "line" ? config2.chartType : config2.type === "pie" || config2.type === "bar" || config2.type === "line" ? config2.type : "bar";
|
|
629
|
+
} else if (hasAggregationLikeData || typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
|
|
625
630
|
config2.view = "chart";
|
|
626
|
-
config2.chartType =
|
|
627
|
-
config2.data = resolvedRows2;
|
|
631
|
+
config2.chartType = config2.chartType || config2.type || "bar";
|
|
628
632
|
} else {
|
|
629
633
|
config2.view = "table";
|
|
630
|
-
config2.data = Array.isArray(config2.data) ? config2.data : Array.isArray(config2) ? config2 : [];
|
|
631
634
|
}
|
|
632
635
|
}
|
|
633
|
-
const resolvedRows = resolveStructuredRows(config2);
|
|
634
636
|
const normalizedConfig = __spreadProps(__spreadValues({}, config2), {
|
|
635
637
|
data: normalizeTabularRows(resolvedRows, config2.columns)
|
|
636
638
|
});
|
package/dist/server.js
CHANGED
|
@@ -3913,7 +3913,7 @@ var Pipeline = class {
|
|
|
3913
3913
|
async initialize() {
|
|
3914
3914
|
var _a, _b;
|
|
3915
3915
|
if (this.initialised) return;
|
|
3916
|
-
const CHART_MARKER = "<!--
|
|
3916
|
+
const CHART_MARKER = "<!-- UI_PROTOCOL_V6 -->";
|
|
3917
3917
|
const chartInstruction = `
|
|
3918
3918
|
|
|
3919
3919
|
${CHART_MARKER}
|
|
@@ -3921,16 +3921,16 @@ ${CHART_MARKER}
|
|
|
3921
3921
|
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
3922
3922
|
|
|
3923
3923
|
1. VIEW SELECTION
|
|
3924
|
-
- Use "
|
|
3925
|
-
- Use "
|
|
3926
|
-
- Use "table" for
|
|
3924
|
+
- Use "carousel" for browsing specific products, items, or a catalog. This is the DEFAULT for "show me", "what are", or "find me" requests for a specific category (e.g. "beauty").
|
|
3925
|
+
- Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
|
|
3926
|
+
- Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
|
|
3927
3927
|
|
|
3928
3928
|
2. REQUIRED JSON SHAPE
|
|
3929
3929
|
{
|
|
3930
3930
|
"view": "chart" | "carousel" | "table",
|
|
3931
3931
|
"title": "Short heading",
|
|
3932
3932
|
"description": "One sentence describing the view",
|
|
3933
|
-
"chartType": "pie" | "bar" | "line",
|
|
3933
|
+
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
3934
3934
|
"xAxisKey": "label",
|
|
3935
3935
|
"dataKeys": ["value"],
|
|
3936
3936
|
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
@@ -3939,41 +3939,42 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
3939
3939
|
}
|
|
3940
3940
|
|
|
3941
3941
|
3. DATA RULES
|
|
3942
|
-
- Build the UI payload from retrieved context only. Do not invent products
|
|
3943
|
-
-
|
|
3944
|
-
- For
|
|
3945
|
-
-
|
|
3946
|
-
- If stock information exists, preserve it in each row with fields like "inStock", "inStockCount", "outOfStockCount", or "stockStatus".
|
|
3947
|
-
- If the user asks to highlight what is in stock, include those stock-related fields in the chart data and mention the pattern in "insights".
|
|
3948
|
-
- For carousel rows, include product-friendly fields such as id, name, brand, price, image, link, category, stockStatus.
|
|
3949
|
-
- For tables, keep "data" row-oriented and include "columns" only as dynamic field keys/order hints from the fetched data, never as hardcoded UI labels.
|
|
3942
|
+
- Build the UI payload from retrieved context only. Do not invent products or values.
|
|
3943
|
+
- For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
|
|
3944
|
+
- For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
|
|
3945
|
+
- If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
|
|
3950
3946
|
|
|
3951
3947
|
4. FORMAT RULES
|
|
3952
|
-
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
3953
|
-
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
3954
3948
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
3955
|
-
-
|
|
3956
|
-
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
3949
|
+
- Put natural language explanation before or after the block, not inside.
|
|
3957
3950
|
|
|
3958
|
-
5.
|
|
3959
|
-
User: "
|
|
3951
|
+
5. EXAMPLES
|
|
3952
|
+
User: "show me beauty products"
|
|
3953
|
+
Assistant:
|
|
3954
|
+
\`\`\`ui
|
|
3955
|
+
{
|
|
3956
|
+
"view": "carousel",
|
|
3957
|
+
"title": "Beauty Products",
|
|
3958
|
+
"description": "Browse our latest skincare and makeup collection.",
|
|
3959
|
+
"data": [
|
|
3960
|
+
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
|
|
3961
|
+
{ "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
|
|
3962
|
+
]
|
|
3963
|
+
}
|
|
3964
|
+
\`\`\`
|
|
3965
|
+
|
|
3966
|
+
User: "breakdown of products by category"
|
|
3960
3967
|
Assistant:
|
|
3961
3968
|
\`\`\`ui
|
|
3962
3969
|
{
|
|
3963
3970
|
"view": "chart",
|
|
3964
|
-
"title": "
|
|
3965
|
-
"description": "Pie chart showing product count by category with stock signals preserved per slice.",
|
|
3971
|
+
"title": "Category Breakdown",
|
|
3966
3972
|
"chartType": "pie",
|
|
3967
3973
|
"xAxisKey": "label",
|
|
3968
3974
|
"dataKeys": ["value"],
|
|
3969
|
-
"insights": [
|
|
3970
|
-
"Beauty has the highest product count.",
|
|
3971
|
-
"Electronics has the largest number of in-stock products."
|
|
3972
|
-
],
|
|
3973
3975
|
"data": [
|
|
3974
|
-
{ "label": "Beauty", "value":
|
|
3975
|
-
{ "label": "
|
|
3976
|
-
{ "label": "Home", "value": 5, "inStockCount": 2, "outOfStockCount": 3 }
|
|
3976
|
+
{ "label": "Beauty", "value": 15 },
|
|
3977
|
+
{ "label": "Fragrances", "value": 8 }
|
|
3977
3978
|
]
|
|
3978
3979
|
}
|
|
3979
3980
|
\`\`\``;
|
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.8",
|
|
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",
|
|
@@ -442,36 +442,47 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
442
442
|
.trim();
|
|
443
443
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
444
444
|
const config = { ...parsed } as Partial<RawUIConfig> & Record<string, unknown>;
|
|
445
|
+
const resolvedRows = resolveStructuredRows(config);
|
|
445
446
|
|
|
446
|
-
//
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
447
|
+
// ─── Intent Healing & Auto-Detection ───────────────────────────────────
|
|
448
|
+
|
|
449
|
+
const hasProductLikeData = resolvedRows.length > 0 &&
|
|
450
|
+
typeof resolvedRows[0] === 'object' && resolvedRows[0] !== null &&
|
|
451
|
+
!Array.isArray(resolvedRows[0]) &&
|
|
452
|
+
(['price', 'brand', 'image', 'link', 'thumbnail'].some(key => key in resolvedRows[0]) ||
|
|
453
|
+
Object.keys(resolvedRows[0]).length >= 4);
|
|
454
|
+
|
|
455
|
+
const hasAggregationLikeData = resolvedRows.length > 0 &&
|
|
456
|
+
typeof resolvedRows[0] === 'object' && resolvedRows[0] !== null &&
|
|
457
|
+
!Array.isArray(resolvedRows[0]) &&
|
|
458
|
+
(['value', 'count', 'total', 'percentage'].some(key => key in resolvedRows[0]) ||
|
|
459
|
+
(Object.keys(resolvedRows[0]).length <= 3 && Object.values(resolvedRows[0]).some(v => typeof v === 'number')));
|
|
460
|
+
|
|
461
|
+
// 1. Healing: Override explicit view if it contradicts the data shape
|
|
462
|
+
if (config.view === 'chart' && hasProductLikeData && !hasAggregationLikeData) {
|
|
463
|
+
config.view = 'carousel';
|
|
464
|
+
} else if (config.view === 'carousel' && hasAggregationLikeData && !hasProductLikeData) {
|
|
465
|
+
config.view = 'chart';
|
|
466
|
+
config.chartType = (config.chartType as 'pie' | 'bar' | 'line') || 'bar';
|
|
467
|
+
}
|
|
451
468
|
|
|
452
|
-
|
|
469
|
+
// 2. Auto-Detection: Fill in missing view
|
|
470
|
+
if (!config.view) {
|
|
471
|
+
if (config.type === 'products' || Array.isArray(config.items) || hasProductLikeData) {
|
|
453
472
|
config.view = 'carousel';
|
|
454
|
-
config.data = resolvedRows;
|
|
455
473
|
} else if (
|
|
474
|
+
hasAggregationLikeData ||
|
|
456
475
|
(typeof config.type === 'string' && ['pie', 'bar', 'line'].includes(config.type)) ||
|
|
457
476
|
(typeof config.chartType === 'string' && ['pie', 'bar', 'line'].includes(config.chartType))
|
|
458
477
|
) {
|
|
459
|
-
const resolvedChartType =
|
|
460
|
-
config.chartType === 'pie' || config.chartType === 'bar' || config.chartType === 'line'
|
|
461
|
-
? config.chartType
|
|
462
|
-
: config.type === 'pie' || config.type === 'bar' || config.type === 'line'
|
|
463
|
-
? config.type
|
|
464
|
-
: 'bar';
|
|
465
478
|
config.view = 'chart';
|
|
466
|
-
config.chartType =
|
|
467
|
-
|
|
479
|
+
config.chartType = (config.chartType as 'pie' | 'bar' | 'line') ||
|
|
480
|
+
(config.type as 'pie' | 'bar' | 'line') || 'bar';
|
|
468
481
|
} else {
|
|
469
482
|
config.view = 'table';
|
|
470
|
-
config.data = Array.isArray(config.data) ? config.data : (Array.isArray(config) ? config : []);
|
|
471
483
|
}
|
|
472
484
|
}
|
|
473
485
|
|
|
474
|
-
const resolvedRows = resolveStructuredRows(config);
|
|
475
486
|
const normalizedConfig: UIConfig = {
|
|
476
487
|
...(config as Omit<UIConfig, 'data'>),
|
|
477
488
|
data: normalizeTabularRows(resolvedRows, config.columns),
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -101,22 +101,22 @@ export class Pipeline {
|
|
|
101
101
|
|
|
102
102
|
// Augment system prompt with a Universal Visualization Protocol
|
|
103
103
|
// We use a unique marker to ensure this is only injected once but is ALWAYS present.
|
|
104
|
-
const CHART_MARKER = '<!--
|
|
104
|
+
const CHART_MARKER = '<!-- UI_PROTOCOL_V6 -->';
|
|
105
105
|
const chartInstruction = `\n\n${CHART_MARKER}
|
|
106
106
|
### UNIVERSAL UI PROTOCOL
|
|
107
107
|
When the user asks for a visual representation, comparison, distribution, breakdown, table, list, catalog, products, carousel, stock view, or category summary, you MUST include exactly one \`\`\`ui\`\`\` block.
|
|
108
108
|
|
|
109
109
|
1. VIEW SELECTION
|
|
110
|
-
- Use "
|
|
111
|
-
- Use "
|
|
112
|
-
- Use "table" for
|
|
110
|
+
- Use "carousel" for browsing specific products, items, or a catalog. This is the DEFAULT for "show me", "what are", or "find me" requests for a specific category (e.g. "beauty").
|
|
111
|
+
- Use "chart" ONLY for numerical aggregations: distributions, percentages, counts, comparisons over time, or trends (e.g. "how many beauty products?").
|
|
112
|
+
- Use "table" for detailed technical specifications, row-heavy comparisons, or when the user explicitly asks for a list/table format.
|
|
113
113
|
|
|
114
114
|
2. REQUIRED JSON SHAPE
|
|
115
115
|
{
|
|
116
116
|
"view": "chart" | "carousel" | "table",
|
|
117
117
|
"title": "Short heading",
|
|
118
118
|
"description": "One sentence describing the view",
|
|
119
|
-
"chartType": "pie" | "bar" | "line",
|
|
119
|
+
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
120
120
|
"xAxisKey": "label",
|
|
121
121
|
"dataKeys": ["value"],
|
|
122
122
|
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
@@ -125,41 +125,42 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
3. DATA RULES
|
|
128
|
-
- Build the UI payload from retrieved context only. Do not invent products
|
|
129
|
-
-
|
|
130
|
-
- For
|
|
131
|
-
-
|
|
132
|
-
- If stock information exists, preserve it in each row with fields like "inStock", "inStockCount", "outOfStockCount", or "stockStatus".
|
|
133
|
-
- If the user asks to highlight what is in stock, include those stock-related fields in the chart data and mention the pattern in "insights".
|
|
134
|
-
- For carousel rows, include product-friendly fields such as id, name, brand, price, image, link, category, stockStatus.
|
|
135
|
-
- For tables, keep "data" row-oriented and include "columns" only as dynamic field keys/order hints from the fetched data, never as hardcoded UI labels.
|
|
128
|
+
- Build the UI payload from retrieved context only. Do not invent products or values.
|
|
129
|
+
- For CAROUSEL: "data" must be a list of product objects (id, name, brand, price, image, link).
|
|
130
|
+
- For CHART: "data" must be aggregated counts or sums. Never put raw product lists in a chart view.
|
|
131
|
+
- If the user asks for "products in beauty", do NOT return a pie chart of categories; return a carousel of the beauty products themselves.
|
|
136
132
|
|
|
137
133
|
4. FORMAT RULES
|
|
138
|
-
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
139
|
-
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
140
134
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
141
|
-
-
|
|
142
|
-
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
135
|
+
- Put natural language explanation before or after the block, not inside.
|
|
143
136
|
|
|
144
|
-
5.
|
|
145
|
-
User: "
|
|
137
|
+
5. EXAMPLES
|
|
138
|
+
User: "show me beauty products"
|
|
139
|
+
Assistant:
|
|
140
|
+
\`\`\`ui
|
|
141
|
+
{
|
|
142
|
+
"view": "carousel",
|
|
143
|
+
"title": "Beauty Products",
|
|
144
|
+
"description": "Browse our latest skincare and makeup collection.",
|
|
145
|
+
"data": [
|
|
146
|
+
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
|
|
147
|
+
{ "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
User: "breakdown of products by category"
|
|
146
153
|
Assistant:
|
|
147
154
|
\`\`\`ui
|
|
148
155
|
{
|
|
149
156
|
"view": "chart",
|
|
150
|
-
"title": "
|
|
151
|
-
"description": "Pie chart showing product count by category with stock signals preserved per slice.",
|
|
157
|
+
"title": "Category Breakdown",
|
|
152
158
|
"chartType": "pie",
|
|
153
159
|
"xAxisKey": "label",
|
|
154
160
|
"dataKeys": ["value"],
|
|
155
|
-
"insights": [
|
|
156
|
-
"Beauty has the highest product count.",
|
|
157
|
-
"Electronics has the largest number of in-stock products."
|
|
158
|
-
],
|
|
159
161
|
"data": [
|
|
160
|
-
{ "label": "Beauty", "value":
|
|
161
|
-
{ "label": "
|
|
162
|
-
{ "label": "Home", "value": 5, "inStockCount": 2, "outOfStockCount": 3 }
|
|
162
|
+
{ "label": "Beauty", "value": 15 },
|
|
163
|
+
{ "label": "Fragrances", "value": 8 }
|
|
163
164
|
]
|
|
164
165
|
}
|
|
165
166
|
\`\`\``;
|