@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/{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/utils/UITransformer.ts +535 -0
package/dist/server.js
CHANGED
|
@@ -3913,18 +3913,17 @@ 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}
|
|
3920
|
-
### UNIVERSAL UI PROTOCOL
|
|
3921
|
-
|
|
3922
|
-
NEVER output naked JSON. If you provide a visualization, do not also provide a markdown table of the same data unless explicitly asked.
|
|
3920
|
+
### UNIVERSAL UI PROTOCOL
|
|
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.
|
|
3923
3922
|
|
|
3924
3923
|
1. VIEW SELECTION
|
|
3925
|
-
- Use "carousel" for browsing products, items, or
|
|
3926
|
-
- Use "chart" ONLY for numerical aggregations
|
|
3927
|
-
- Use "table" for technical
|
|
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.
|
|
3928
3927
|
|
|
3929
3928
|
2. REQUIRED JSON SHAPE
|
|
3930
3929
|
{
|
|
@@ -3932,31 +3931,52 @@ NEVER output naked JSON. If you provide a visualization, do not also provide a m
|
|
|
3932
3931
|
"title": "Short heading",
|
|
3933
3932
|
"description": "One sentence describing the view",
|
|
3934
3933
|
"chartType": "pie" | "bar" | "line", // Required if view is "chart"
|
|
3935
|
-
"
|
|
3934
|
+
"xAxisKey": "label",
|
|
3935
|
+
"dataKeys": ["value"],
|
|
3936
|
+
"columns": ["dynamicFieldKey1", "dynamicFieldKey2"],
|
|
3937
|
+
"insights": ["Short takeaway 1", "Short takeaway 2"],
|
|
3938
|
+
"data": []
|
|
3936
3939
|
}
|
|
3937
3940
|
|
|
3938
3941
|
3. DATA RULES
|
|
3939
|
-
- Build the UI payload from retrieved context
|
|
3940
|
-
- For CAROUSEL: "data"
|
|
3941
|
-
-
|
|
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.
|
|
3942
3946
|
|
|
3943
3947
|
4. FORMAT RULES
|
|
3944
|
-
-
|
|
3945
|
-
-
|
|
3948
|
+
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
3949
|
+
- Put natural language explanation before or after the block, not inside.
|
|
3946
3950
|
|
|
3947
|
-
5.
|
|
3948
|
-
User: "
|
|
3949
|
-
Assistant:
|
|
3951
|
+
5. EXAMPLES
|
|
3952
|
+
User: "show me beauty products"
|
|
3953
|
+
Assistant:
|
|
3950
3954
|
\`\`\`ui
|
|
3951
3955
|
{
|
|
3952
3956
|
"view": "carousel",
|
|
3953
3957
|
"title": "Beauty Products",
|
|
3954
|
-
"description": "
|
|
3958
|
+
"description": "Browse our latest skincare and makeup collection.",
|
|
3955
3959
|
"data": [
|
|
3956
|
-
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "
|
|
3960
|
+
{ "id": "1", "name": "Mascara", "brand": "Essence", "price": "$9.99", "image": "...", "link": "..." },
|
|
3961
|
+
{ "id": "2", "name": "Lipstick", "brand": "Chic", "price": "$12.99", "image": "...", "link": "..." }
|
|
3957
3962
|
]
|
|
3958
3963
|
}
|
|
3959
3964
|
\`\`\`
|
|
3965
|
+
|
|
3966
|
+
User: "breakdown of products by category"
|
|
3967
|
+
Assistant:
|
|
3968
|
+
\`\`\`ui
|
|
3969
|
+
{
|
|
3970
|
+
"view": "chart",
|
|
3971
|
+
"title": "Category Breakdown",
|
|
3972
|
+
"chartType": "pie",
|
|
3973
|
+
"xAxisKey": "label",
|
|
3974
|
+
"dataKeys": ["value"],
|
|
3975
|
+
"data": [
|
|
3976
|
+
{ "label": "Beauty", "value": 15 },
|
|
3977
|
+
{ "label": "Fragrances", "value": 8 }
|
|
3978
|
+
]
|
|
3979
|
+
}
|
|
3960
3980
|
\`\`\``;
|
|
3961
3981
|
if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
|
|
3962
3982
|
this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
|
|
@@ -4165,8 +4185,7 @@ Assistant: "I found several beauty products in our catalog:"
|
|
|
4165
4185
|
sources = sources.slice(0, topK);
|
|
4166
4186
|
}
|
|
4167
4187
|
let context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
4168
|
-
|
|
4169
|
-
Metadata: ${JSON.stringify(m.metadata)}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
4188
|
+
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
4170
4189
|
if (graphData && graphData.nodes.length > 0) {
|
|
4171
4190
|
const graphContext = graphData.nodes.map(
|
|
4172
4191
|
(n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
|
|
@@ -4903,6 +4922,353 @@ init_UniversalVectorProvider();
|
|
|
4903
4922
|
|
|
4904
4923
|
// src/handlers/index.ts
|
|
4905
4924
|
var import_server = require("next/server");
|
|
4925
|
+
|
|
4926
|
+
// src/utils/UITransformer.ts
|
|
4927
|
+
var UITransformer = class {
|
|
4928
|
+
/**
|
|
4929
|
+
* Main transformation method
|
|
4930
|
+
* Analyzes user query and retrieved data to determine the best visualization format
|
|
4931
|
+
*
|
|
4932
|
+
* @param userQuery - The original user question/query
|
|
4933
|
+
* @param retrievedData - Vector database retrieval results
|
|
4934
|
+
* @returns Structured JSON response for UI rendering
|
|
4935
|
+
*/
|
|
4936
|
+
static transform(userQuery, retrievedData) {
|
|
4937
|
+
if (!retrievedData || retrievedData.length === 0) {
|
|
4938
|
+
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4939
|
+
}
|
|
4940
|
+
const analysis = this.analyzeData(userQuery, retrievedData);
|
|
4941
|
+
switch (analysis.suggestedType) {
|
|
4942
|
+
case "product_carousel":
|
|
4943
|
+
return this.transformToProductCarousel(retrievedData);
|
|
4944
|
+
case "pie_chart":
|
|
4945
|
+
return this.transformToPieChart(retrievedData);
|
|
4946
|
+
case "bar_chart":
|
|
4947
|
+
return this.transformToBarChart(retrievedData);
|
|
4948
|
+
case "line_chart":
|
|
4949
|
+
return this.transformToLineChart(retrievedData);
|
|
4950
|
+
case "table":
|
|
4951
|
+
return this.transformToTable(retrievedData);
|
|
4952
|
+
default:
|
|
4953
|
+
return this.transformToText(retrievedData);
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
/**
|
|
4957
|
+
* Analyzes the data and query to suggest the best visualization type
|
|
4958
|
+
*/
|
|
4959
|
+
static analyzeData(query, data) {
|
|
4960
|
+
const queryLower = query.toLowerCase();
|
|
4961
|
+
const hasProducts = data.some(
|
|
4962
|
+
(item) => this.isProductData(item)
|
|
4963
|
+
);
|
|
4964
|
+
const hasTimeSeries = data.some(
|
|
4965
|
+
(item) => this.isTimeSeriesData(item)
|
|
4966
|
+
);
|
|
4967
|
+
const hasCategories = this.detectCategories(data).length > 0;
|
|
4968
|
+
const isDistributionQuery = queryLower.includes("distribution") || queryLower.includes("breakdown") || queryLower.includes("percentage") || queryLower.includes("proportion");
|
|
4969
|
+
const isComparisonQuery = queryLower.includes("compare") || queryLower.includes("vs") || queryLower.includes("difference");
|
|
4970
|
+
const isTrendQuery = queryLower.includes("trend") || queryLower.includes("over time") || queryLower.includes("growth") || queryLower.includes("decline");
|
|
4971
|
+
if (hasProducts && !hasTimeSeries && !isDistributionQuery) {
|
|
4972
|
+
return { suggestedType: "product_carousel", confidence: 0.95, hasProducts, hasTimeSeries, hasCategories };
|
|
4973
|
+
}
|
|
4974
|
+
if (isTrendQuery && hasTimeSeries) {
|
|
4975
|
+
return { suggestedType: "line_chart", confidence: 0.9, hasProducts, hasTimeSeries, hasCategories };
|
|
4976
|
+
}
|
|
4977
|
+
if (isDistributionQuery && hasCategories) {
|
|
4978
|
+
return { suggestedType: "pie_chart", confidence: 0.85, hasProducts, hasTimeSeries, hasCategories };
|
|
4979
|
+
}
|
|
4980
|
+
if (isComparisonQuery && hasCategories && data.length > 2) {
|
|
4981
|
+
return { suggestedType: "bar_chart", confidence: 0.8, hasProducts, hasTimeSeries, hasCategories };
|
|
4982
|
+
}
|
|
4983
|
+
if (data.length > 5 && this.hasMultipleFields(data)) {
|
|
4984
|
+
return { suggestedType: "table", confidence: 0.75, hasProducts, hasTimeSeries, hasCategories };
|
|
4985
|
+
}
|
|
4986
|
+
return { suggestedType: "text", confidence: 0.5, hasProducts, hasTimeSeries, hasCategories };
|
|
4987
|
+
}
|
|
4988
|
+
/**
|
|
4989
|
+
* Transform data to product carousel format
|
|
4990
|
+
*/
|
|
4991
|
+
static transformToProductCarousel(data) {
|
|
4992
|
+
const products = data.filter((item) => this.isProductData(item)).map((item) => this.extractProductInfo(item)).filter((p) => p !== null);
|
|
4993
|
+
return {
|
|
4994
|
+
type: "product_carousel",
|
|
4995
|
+
title: "Recommended Products",
|
|
4996
|
+
description: `Found ${products.length} relevant products`,
|
|
4997
|
+
data: products
|
|
4998
|
+
};
|
|
4999
|
+
}
|
|
5000
|
+
/**
|
|
5001
|
+
* Transform data to pie chart format
|
|
5002
|
+
*/
|
|
5003
|
+
static transformToPieChart(data) {
|
|
5004
|
+
const categories = this.detectCategories(data);
|
|
5005
|
+
const categoryData = this.aggregateByCategory(data, categories);
|
|
5006
|
+
const pieData = Object.entries(categoryData).map(([label, count]) => ({
|
|
5007
|
+
label,
|
|
5008
|
+
value: count,
|
|
5009
|
+
inStock: this.checkStockStatus(label, data)
|
|
5010
|
+
}));
|
|
5011
|
+
return {
|
|
5012
|
+
type: "pie_chart",
|
|
5013
|
+
title: "Distribution by Category",
|
|
5014
|
+
description: `Showing breakdown across ${categories.length} categories`,
|
|
5015
|
+
data: pieData
|
|
5016
|
+
};
|
|
5017
|
+
}
|
|
5018
|
+
/**
|
|
5019
|
+
* Transform data to bar chart format
|
|
5020
|
+
*/
|
|
5021
|
+
static transformToBarChart(data) {
|
|
5022
|
+
const categories = this.detectCategories(data);
|
|
5023
|
+
const categoryData = this.aggregateByCategory(data, categories);
|
|
5024
|
+
const barData = Object.entries(categoryData).map(([category, value]) => ({
|
|
5025
|
+
category,
|
|
5026
|
+
value,
|
|
5027
|
+
inStock: this.checkStockStatus(category, data)
|
|
5028
|
+
}));
|
|
5029
|
+
return {
|
|
5030
|
+
type: "bar_chart",
|
|
5031
|
+
title: "Comparison by Category",
|
|
5032
|
+
description: `Comparing ${categories.length} categories`,
|
|
5033
|
+
data: barData
|
|
5034
|
+
};
|
|
5035
|
+
}
|
|
5036
|
+
/**
|
|
5037
|
+
* Transform data to line chart format
|
|
5038
|
+
*/
|
|
5039
|
+
static transformToLineChart(data) {
|
|
5040
|
+
const timePoints = this.extractTimeSeriesData(data);
|
|
5041
|
+
const lineData = timePoints.map((point) => ({
|
|
5042
|
+
timestamp: point.timestamp,
|
|
5043
|
+
value: point.value,
|
|
5044
|
+
label: point.label
|
|
5045
|
+
}));
|
|
5046
|
+
return {
|
|
5047
|
+
type: "line_chart",
|
|
5048
|
+
title: "Trend Over Time",
|
|
5049
|
+
description: `Showing ${lineData.length} data points`,
|
|
5050
|
+
data: lineData
|
|
5051
|
+
};
|
|
5052
|
+
}
|
|
5053
|
+
/**
|
|
5054
|
+
* Transform data to table format
|
|
5055
|
+
*/
|
|
5056
|
+
static transformToTable(data) {
|
|
5057
|
+
const columns = this.extractTableColumns(data);
|
|
5058
|
+
const rows = data.map((item) => this.extractTableRow(item, columns));
|
|
5059
|
+
const tableData = {
|
|
5060
|
+
columns,
|
|
5061
|
+
rows
|
|
5062
|
+
};
|
|
5063
|
+
return {
|
|
5064
|
+
type: "table",
|
|
5065
|
+
title: "Detailed Results",
|
|
5066
|
+
description: `Showing ${data.length} results`,
|
|
5067
|
+
data: tableData
|
|
5068
|
+
};
|
|
5069
|
+
}
|
|
5070
|
+
/**
|
|
5071
|
+
* Transform data to text format (fallback)
|
|
5072
|
+
*/
|
|
5073
|
+
static transformToText(data) {
|
|
5074
|
+
const textContent = data.map((item) => item.content).join("\n\n");
|
|
5075
|
+
return this.createTextResponse(
|
|
5076
|
+
"Search Results",
|
|
5077
|
+
textContent,
|
|
5078
|
+
`Found ${data.length} relevant results`
|
|
5079
|
+
);
|
|
5080
|
+
}
|
|
5081
|
+
/**
|
|
5082
|
+
* Helper: Create text response
|
|
5083
|
+
*/
|
|
5084
|
+
static createTextResponse(title, content, description) {
|
|
5085
|
+
return {
|
|
5086
|
+
type: "text",
|
|
5087
|
+
title,
|
|
5088
|
+
description,
|
|
5089
|
+
data: { content }
|
|
5090
|
+
};
|
|
5091
|
+
}
|
|
5092
|
+
/**
|
|
5093
|
+
* Helper: Check if data item is product-related
|
|
5094
|
+
*/
|
|
5095
|
+
static isProductData(item) {
|
|
5096
|
+
const content = (item.content || "").toLowerCase();
|
|
5097
|
+
const productKeywords = ["product", "price", "stock", "item", "sku", "brand", "model"];
|
|
5098
|
+
return productKeywords.some((kw) => content.includes(kw)) || Object.keys(item.metadata || {}).some(
|
|
5099
|
+
(k) => ["name", "price", "product", "sku"].includes(k.toLowerCase())
|
|
5100
|
+
);
|
|
5101
|
+
}
|
|
5102
|
+
/**
|
|
5103
|
+
* Helper: Check if data contains time series
|
|
5104
|
+
*/
|
|
5105
|
+
static isTimeSeriesData(item) {
|
|
5106
|
+
const content = (item.content || "").toLowerCase();
|
|
5107
|
+
const timeKeywords = ["date", "time", "year", "month", "week", "day", "hour", "trend", "historical"];
|
|
5108
|
+
return timeKeywords.some((kw) => content.includes(kw)) || Object.keys(item.metadata || {}).some(
|
|
5109
|
+
(k) => ["date", "timestamp", "time", "period"].includes(k.toLowerCase())
|
|
5110
|
+
);
|
|
5111
|
+
}
|
|
5112
|
+
/**
|
|
5113
|
+
* Helper: Extract product information from vector match
|
|
5114
|
+
*/
|
|
5115
|
+
static extractProductInfo(item) {
|
|
5116
|
+
const meta = item.metadata || {};
|
|
5117
|
+
if (meta.name || meta.product) {
|
|
5118
|
+
return {
|
|
5119
|
+
id: item.id,
|
|
5120
|
+
name: meta.name || meta.product,
|
|
5121
|
+
price: meta.price,
|
|
5122
|
+
image: meta.image || meta.imageUrl,
|
|
5123
|
+
brand: meta.brand,
|
|
5124
|
+
description: item.content,
|
|
5125
|
+
inStock: this.determineStockStatus(item)
|
|
5126
|
+
};
|
|
5127
|
+
}
|
|
5128
|
+
const nameMatch = item.content.match(/(?:Product|Item|Name):\s*([^\n]+)/i);
|
|
5129
|
+
const priceMatch = item.content.match(/(?:Price|Cost):\s*\$?([\d.]+)/i);
|
|
5130
|
+
if (nameMatch) {
|
|
5131
|
+
return {
|
|
5132
|
+
id: item.id,
|
|
5133
|
+
name: nameMatch[1],
|
|
5134
|
+
price: priceMatch ? parseFloat(priceMatch[1]) : void 0,
|
|
5135
|
+
description: item.content,
|
|
5136
|
+
inStock: this.determineStockStatus(item)
|
|
5137
|
+
};
|
|
5138
|
+
}
|
|
5139
|
+
return null;
|
|
5140
|
+
}
|
|
5141
|
+
/**
|
|
5142
|
+
* Helper: Detect categories in data
|
|
5143
|
+
*/
|
|
5144
|
+
static detectCategories(data) {
|
|
5145
|
+
const categories = /* @__PURE__ */ new Set();
|
|
5146
|
+
data.forEach((item) => {
|
|
5147
|
+
const meta = item.metadata || {};
|
|
5148
|
+
if (meta.category) {
|
|
5149
|
+
categories.add(String(meta.category));
|
|
5150
|
+
}
|
|
5151
|
+
if (meta.type) {
|
|
5152
|
+
categories.add(String(meta.type));
|
|
5153
|
+
}
|
|
5154
|
+
if (meta.tag) {
|
|
5155
|
+
const tags = Array.isArray(meta.tag) ? meta.tag : [meta.tag];
|
|
5156
|
+
tags.forEach((t) => categories.add(String(t)));
|
|
5157
|
+
}
|
|
5158
|
+
const categoryMatch = item.content.match(/(?:Category|Type|Class):\s*([^\n]+)/i);
|
|
5159
|
+
if (categoryMatch) {
|
|
5160
|
+
categories.add(categoryMatch[1].trim());
|
|
5161
|
+
}
|
|
5162
|
+
});
|
|
5163
|
+
return Array.from(categories);
|
|
5164
|
+
}
|
|
5165
|
+
/**
|
|
5166
|
+
* Helper: Aggregate data by category
|
|
5167
|
+
*/
|
|
5168
|
+
static aggregateByCategory(data, categories) {
|
|
5169
|
+
const result = {};
|
|
5170
|
+
categories.forEach((cat) => {
|
|
5171
|
+
result[cat] = 0;
|
|
5172
|
+
});
|
|
5173
|
+
data.forEach((item) => {
|
|
5174
|
+
const meta = item.metadata || {};
|
|
5175
|
+
const itemCategory = meta.category || meta.type || "Other";
|
|
5176
|
+
if (result.hasOwnProperty(itemCategory)) {
|
|
5177
|
+
result[itemCategory]++;
|
|
5178
|
+
} else {
|
|
5179
|
+
result["Other"] = (result["Other"] || 0) + 1;
|
|
5180
|
+
}
|
|
5181
|
+
});
|
|
5182
|
+
return result;
|
|
5183
|
+
}
|
|
5184
|
+
/**
|
|
5185
|
+
* Helper: Extract time series data
|
|
5186
|
+
*/
|
|
5187
|
+
static extractTimeSeriesData(data) {
|
|
5188
|
+
return data.map((item) => {
|
|
5189
|
+
const meta = item.metadata || {};
|
|
5190
|
+
return {
|
|
5191
|
+
timestamp: meta.timestamp || meta.date || (/* @__PURE__ */ new Date()).toISOString(),
|
|
5192
|
+
value: meta.value || item.score || 0,
|
|
5193
|
+
label: meta.label || item.content.substring(0, 50)
|
|
5194
|
+
};
|
|
5195
|
+
});
|
|
5196
|
+
}
|
|
5197
|
+
/**
|
|
5198
|
+
* Helper: Extract table columns
|
|
5199
|
+
*/
|
|
5200
|
+
static extractTableColumns(data) {
|
|
5201
|
+
const columnSet = /* @__PURE__ */ new Set();
|
|
5202
|
+
columnSet.add("Content");
|
|
5203
|
+
data.forEach((item) => {
|
|
5204
|
+
Object.keys(item.metadata || {}).forEach((key) => {
|
|
5205
|
+
columnSet.add(key.charAt(0).toUpperCase() + key.slice(1));
|
|
5206
|
+
});
|
|
5207
|
+
});
|
|
5208
|
+
return Array.from(columnSet);
|
|
5209
|
+
}
|
|
5210
|
+
/**
|
|
5211
|
+
* Helper: Extract table row
|
|
5212
|
+
*/
|
|
5213
|
+
static extractTableRow(item, columns) {
|
|
5214
|
+
const meta = item.metadata || {};
|
|
5215
|
+
return columns.map((col) => {
|
|
5216
|
+
if (col === "Content") {
|
|
5217
|
+
return item.content.substring(0, 100);
|
|
5218
|
+
}
|
|
5219
|
+
const metaKey = col.charAt(0).toLowerCase() + col.slice(1);
|
|
5220
|
+
const value = meta[metaKey];
|
|
5221
|
+
return value !== void 0 ? String(value) : "";
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5224
|
+
/**
|
|
5225
|
+
* Helper: Check stock status
|
|
5226
|
+
*/
|
|
5227
|
+
static checkStockStatus(category, data) {
|
|
5228
|
+
const item = data.find((d) => {
|
|
5229
|
+
const meta = d.metadata || {};
|
|
5230
|
+
return meta.category === category || meta.type === category;
|
|
5231
|
+
});
|
|
5232
|
+
return this.determineStockStatus(item || {});
|
|
5233
|
+
}
|
|
5234
|
+
/**
|
|
5235
|
+
* Helper: Determine if item is in stock
|
|
5236
|
+
*/
|
|
5237
|
+
static determineStockStatus(item) {
|
|
5238
|
+
const meta = item.metadata || {};
|
|
5239
|
+
if (meta.inStock !== void 0) {
|
|
5240
|
+
return Boolean(meta.inStock);
|
|
5241
|
+
}
|
|
5242
|
+
if (meta.stock !== void 0) {
|
|
5243
|
+
return Boolean(meta.stock);
|
|
5244
|
+
}
|
|
5245
|
+
if (meta.available !== void 0) {
|
|
5246
|
+
return Boolean(meta.available);
|
|
5247
|
+
}
|
|
5248
|
+
const content = (item.content || "").toLowerCase();
|
|
5249
|
+
if (content.includes("out of stock") || content.includes("unavailable")) {
|
|
5250
|
+
return false;
|
|
5251
|
+
}
|
|
5252
|
+
if (content.includes("in stock") || content.includes("available")) {
|
|
5253
|
+
return true;
|
|
5254
|
+
}
|
|
5255
|
+
return true;
|
|
5256
|
+
}
|
|
5257
|
+
/**
|
|
5258
|
+
* Helper: Check if data has multiple fields
|
|
5259
|
+
*/
|
|
5260
|
+
static hasMultipleFields(data) {
|
|
5261
|
+
const fieldCount = /* @__PURE__ */ new Set();
|
|
5262
|
+
data.forEach((item) => {
|
|
5263
|
+
Object.keys(item.metadata || {}).forEach((key) => {
|
|
5264
|
+
fieldCount.add(key);
|
|
5265
|
+
});
|
|
5266
|
+
});
|
|
5267
|
+
return fieldCount.size > 2;
|
|
5268
|
+
}
|
|
5269
|
+
};
|
|
5270
|
+
|
|
5271
|
+
// src/handlers/index.ts
|
|
4906
5272
|
function sseFrame(payload) {
|
|
4907
5273
|
return `data: ${JSON.stringify(payload)}
|
|
4908
5274
|
|
|
@@ -4916,6 +5282,11 @@ function sseTextFrame(text) {
|
|
|
4916
5282
|
function sseMetaFrame(meta) {
|
|
4917
5283
|
return `data: ${JSON.stringify(__spreadValues({ type: "metadata" }, meta != null ? meta : {}))}
|
|
4918
5284
|
|
|
5285
|
+
`;
|
|
5286
|
+
}
|
|
5287
|
+
function sseUIFrame(uiTransformation) {
|
|
5288
|
+
return `data: ${JSON.stringify(__spreadValues({ type: "ui_transformation" }, uiTransformation != null ? uiTransformation : {}))}
|
|
5289
|
+
|
|
4919
5290
|
`;
|
|
4920
5291
|
}
|
|
4921
5292
|
function sseErrorFrame(message) {
|
|
@@ -4979,6 +5350,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
4979
5350
|
enqueue(sseTextFrame(chunk));
|
|
4980
5351
|
} else {
|
|
4981
5352
|
enqueue(sseMetaFrame(chunk));
|
|
5353
|
+
const sources = (chunk == null ? void 0 : chunk.sources) || [];
|
|
5354
|
+
if (sources && sources.length > 0) {
|
|
5355
|
+
try {
|
|
5356
|
+
const uiTransformation = UITransformer.transform(message, sources);
|
|
5357
|
+
enqueue(sseUIFrame(uiTransformation));
|
|
5358
|
+
} catch (transformError) {
|
|
5359
|
+
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
4982
5362
|
}
|
|
4983
5363
|
}
|
|
4984
5364
|
} catch (temp) {
|
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.7.
|
|
3
|
+
"version": "1.7.3",
|
|
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",
|