@retrivora-ai/rag-engine 1.6.4 → 1.6.6
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-EE2Z4HNW.mjs → chunk-5K7EU4KW.mjs} +9 -8
- package/dist/handlers/index.js +9 -8
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.js +9 -8
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +15 -13
- package/src/core/Pipeline.ts +17 -16
|
@@ -2263,14 +2263,15 @@ var Pipeline = class {
|
|
|
2263
2263
|
const chartInstruction = `
|
|
2264
2264
|
|
|
2265
2265
|
${CHART_MARKER}
|
|
2266
|
-
### UNIVERSAL UI PROTOCOL
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
- "chart"
|
|
2271
|
-
- "carousel"
|
|
2272
|
-
- "table"
|
|
2273
|
-
|
|
2266
|
+
### UNIVERSAL UI PROTOCOL
|
|
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
|
+
|
|
2269
|
+
1. VIEW SELECTION
|
|
2270
|
+
- Use "chart" for distributions, percentages, counts, comparisons, trends, or "show me in a chart".
|
|
2271
|
+
- Use "carousel" for browseable product recommendations or when the user asks to see products/items/cards.
|
|
2272
|
+
- Use "table" for tabular/raw detail, explicit table/list requests, or when there are many attributes to compare.
|
|
2273
|
+
|
|
2274
|
+
2. REQUIRED JSON SHAPE
|
|
2274
2275
|
{
|
|
2275
2276
|
"view": "chart" | "carousel" | "table",
|
|
2276
2277
|
"title": "Short heading",
|
package/dist/handlers/index.js
CHANGED
|
@@ -3826,14 +3826,15 @@ var Pipeline = class {
|
|
|
3826
3826
|
const chartInstruction = `
|
|
3827
3827
|
|
|
3828
3828
|
${CHART_MARKER}
|
|
3829
|
-
### UNIVERSAL UI PROTOCOL
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
- "chart"
|
|
3834
|
-
- "carousel"
|
|
3835
|
-
- "table"
|
|
3836
|
-
|
|
3829
|
+
### UNIVERSAL UI PROTOCOL
|
|
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
|
+
|
|
3832
|
+
1. VIEW SELECTION
|
|
3833
|
+
- Use "chart" for distributions, percentages, counts, comparisons, trends, or "show me in a chart".
|
|
3834
|
+
- Use "carousel" for browseable product recommendations or when the user asks to see products/items/cards.
|
|
3835
|
+
- Use "table" for tabular/raw detail, explicit table/list requests, or when there are many attributes to compare.
|
|
3836
|
+
|
|
3837
|
+
2. REQUIRED JSON SHAPE
|
|
3837
3838
|
{
|
|
3838
3839
|
"view": "chart" | "carousel" | "table",
|
|
3839
3840
|
"title": "Short heading",
|
package/dist/handlers/index.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -782,7 +782,7 @@ function MessageBubble({
|
|
|
782
782
|
for (const candidate of payloadCandidates) {
|
|
783
783
|
try {
|
|
784
784
|
const data = JSON.parse(sanitizeJson(candidate));
|
|
785
|
-
const itemSet = Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
785
|
+
const itemSet = Array.isArray(data.data) ? data.data : Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
786
786
|
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
787
787
|
products.push(
|
|
788
788
|
...itemSet.map((item) => {
|
package/dist/index.mjs
CHANGED
|
@@ -745,7 +745,7 @@ function MessageBubble({
|
|
|
745
745
|
for (const candidate of payloadCandidates) {
|
|
746
746
|
try {
|
|
747
747
|
const data = JSON.parse(sanitizeJson(candidate));
|
|
748
|
-
const itemSet = Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
748
|
+
const itemSet = Array.isArray(data.data) ? data.data : Array.isArray(data.items) ? data.items : Array.isArray(data.products) ? data.products : null;
|
|
749
749
|
if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
|
|
750
750
|
products.push(
|
|
751
751
|
...itemSet.map((item) => {
|
package/dist/server.js
CHANGED
|
@@ -3917,14 +3917,15 @@ var Pipeline = class {
|
|
|
3917
3917
|
const chartInstruction = `
|
|
3918
3918
|
|
|
3919
3919
|
${CHART_MARKER}
|
|
3920
|
-
### UNIVERSAL UI PROTOCOL
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
- "chart"
|
|
3925
|
-
- "carousel"
|
|
3926
|
-
- "table"
|
|
3927
|
-
|
|
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.
|
|
3922
|
+
|
|
3923
|
+
1. VIEW SELECTION
|
|
3924
|
+
- Use "chart" for distributions, percentages, counts, comparisons, trends, or "show me in a chart".
|
|
3925
|
+
- Use "carousel" for browseable product recommendations or when the user asks to see products/items/cards.
|
|
3926
|
+
- Use "table" for tabular/raw detail, explicit table/list requests, or when there are many attributes to compare.
|
|
3927
|
+
|
|
3928
|
+
2. REQUIRED JSON SHAPE
|
|
3928
3929
|
{
|
|
3929
3930
|
"view": "chart" | "carousel" | "table",
|
|
3930
3931
|
"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.6",
|
|
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",
|
|
@@ -439,7 +439,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
439
439
|
.trim();
|
|
440
440
|
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
441
441
|
const config = { ...parsed } as Partial<RawUIConfig> & Record<string, unknown>;
|
|
442
|
-
|
|
442
|
+
|
|
443
443
|
// Smart Auto-Detection for legacy or simpler formats
|
|
444
444
|
if (!config.view) {
|
|
445
445
|
if (config.type === 'products' || Array.isArray(config.items)) {
|
|
@@ -502,8 +502,8 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
502
502
|
{hasDescription && (
|
|
503
503
|
<p className={`px-2 ${isCompact ? 'text-xs' : 'text-sm'} text-slate-500 dark:text-white/60`}>{config.description}</p>
|
|
504
504
|
)}
|
|
505
|
-
<DynamicChart
|
|
506
|
-
config={{
|
|
505
|
+
<DynamicChart
|
|
506
|
+
config={{
|
|
507
507
|
type: (config.chartType || 'bar') as 'bar' | 'line' | 'pie',
|
|
508
508
|
data: config.data as unknown as Record<string, string | number>[],
|
|
509
509
|
xAxisKey: config.xAxisKey,
|
|
@@ -629,9 +629,10 @@ export function MessageBubble({
|
|
|
629
629
|
try {
|
|
630
630
|
const data = JSON.parse(sanitizeJson(candidate));
|
|
631
631
|
const itemSet =
|
|
632
|
-
Array.isArray(data.
|
|
633
|
-
: Array.isArray(data.
|
|
634
|
-
:
|
|
632
|
+
Array.isArray(data.data) ? data.data
|
|
633
|
+
: Array.isArray(data.items) ? data.items
|
|
634
|
+
: Array.isArray(data.products) ? data.products
|
|
635
|
+
: null;
|
|
635
636
|
|
|
636
637
|
if (
|
|
637
638
|
(data.type === 'products' || data.view === 'carousel' || data.view === 'table' || Array.isArray(data.products)) &&
|
|
@@ -692,13 +693,14 @@ export function MessageBubble({
|
|
|
692
693
|
const processedMarkdown = React.useMemo(() => {
|
|
693
694
|
let raw = structuredContent.payload ? structuredContent.text : (cleanContent || message.content);
|
|
694
695
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
695
|
-
|
|
696
|
+
|
|
696
697
|
// 1. Structural fixes
|
|
697
698
|
raw = raw.replace(/([^\n])\n\|/g, '$1\n\n|') // Ensure blank line before table
|
|
698
|
-
|
|
699
|
+
.replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, '$1\n'); // Remove blank lines between rows
|
|
699
700
|
|
|
700
701
|
// 2. HEALING: Detect naked JSON charts/products and wrap them if markers are missing
|
|
701
|
-
//
|
|
702
|
+
// CRITICAL: DO NOT REVERT THIS REGEX. It must remain non-greedy and position-independent
|
|
703
|
+
// to catch JSON that is not preceded by a newline (common in many LLM outputs).
|
|
702
704
|
if (!isStreaming) {
|
|
703
705
|
// Find potential JSON objects that are not already wrapped in code blocks
|
|
704
706
|
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
@@ -874,8 +876,8 @@ export function MessageBubble({
|
|
|
874
876
|
{/* Avatar */}
|
|
875
877
|
<div
|
|
876
878
|
className={`flex-shrink-0 ${isCompact ? 'w-7 h-7' : 'w-8 h-8'} rounded-full flex items-center justify-center shadow-lg ${isUser
|
|
877
|
-
|
|
878
|
-
|
|
879
|
+
? 'text-white'
|
|
880
|
+
: 'bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80'
|
|
879
881
|
}`}
|
|
880
882
|
style={isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}}
|
|
881
883
|
>
|
|
@@ -886,8 +888,8 @@ export function MessageBubble({
|
|
|
886
888
|
{/* Bubble */}
|
|
887
889
|
<div
|
|
888
890
|
className={`relative ${isCompact ? 'px-3 py-2.5 text-[13px]' : 'px-4 py-3 text-sm'} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser
|
|
889
|
-
|
|
890
|
-
|
|
891
|
+
? 'text-white rounded-tr-sm'
|
|
892
|
+
: 'bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm'
|
|
891
893
|
}`}
|
|
892
894
|
style={
|
|
893
895
|
isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -103,14 +103,15 @@ 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
|
-
- "chart"
|
|
111
|
-
- "carousel"
|
|
112
|
-
- "table"
|
|
113
|
-
|
|
106
|
+
### UNIVERSAL UI PROTOCOL
|
|
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
|
+
|
|
109
|
+
1. VIEW SELECTION
|
|
110
|
+
- Use "chart" for distributions, percentages, counts, comparisons, trends, or "show me in a chart".
|
|
111
|
+
- Use "carousel" for browseable product recommendations or when the user asks to see products/items/cards.
|
|
112
|
+
- Use "table" for tabular/raw detail, explicit table/list requests, or when there are many attributes to compare.
|
|
113
|
+
|
|
114
|
+
2. REQUIRED JSON SHAPE
|
|
114
115
|
{
|
|
115
116
|
"view": "chart" | "carousel" | "table",
|
|
116
117
|
"title": "Short heading",
|
|
@@ -213,7 +214,7 @@ Assistant:
|
|
|
213
214
|
try {
|
|
214
215
|
const chunks = await this.prepareChunks(doc);
|
|
215
216
|
const vectors = await this.processEmbeddings(chunks);
|
|
216
|
-
|
|
217
|
+
|
|
217
218
|
const upsertDocs = chunks.map((chunk, i) => ({
|
|
218
219
|
id: chunk.id,
|
|
219
220
|
vector: vectors[i],
|
|
@@ -315,7 +316,7 @@ Assistant:
|
|
|
315
316
|
*/
|
|
316
317
|
private async processGraphIngestion(docId: string | number, chunks: Chunk[]): Promise<void> {
|
|
317
318
|
console.log(`[Pipeline] Extracting entities for doc ${docId} (${chunks.length} chunks)...`);
|
|
318
|
-
|
|
319
|
+
|
|
319
320
|
const extractionOptions: BatchOptions = {
|
|
320
321
|
batchSize: 2, // Low concurrency for LLM extraction
|
|
321
322
|
maxRetries: 1,
|
|
@@ -386,11 +387,11 @@ Assistant:
|
|
|
386
387
|
// 2. Parallel Retrieval
|
|
387
388
|
const hints = QueryProcessor.extractQueryFieldHints(question, this.config.rag?.filterableFields);
|
|
388
389
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
389
|
-
|
|
390
|
+
|
|
390
391
|
console.log(`[Pipeline] 🧩 Extracted filters:`, JSON.stringify(filter));
|
|
391
392
|
|
|
392
|
-
const { sources: rawSources, graphData } = await this.retrieve(searchQuery, {
|
|
393
|
-
namespace: ns,
|
|
393
|
+
const { sources: rawSources, graphData } = await this.retrieve(searchQuery, {
|
|
394
|
+
namespace: ns,
|
|
394
395
|
topK: topK * 2,
|
|
395
396
|
filter
|
|
396
397
|
});
|
|
@@ -409,7 +410,7 @@ Assistant:
|
|
|
409
410
|
: 'No relevant context found.';
|
|
410
411
|
|
|
411
412
|
if (graphData && graphData.nodes.length > 0) {
|
|
412
|
-
const graphContext = graphData.nodes.map(n =>
|
|
413
|
+
const graphContext = graphData.nodes.map(n =>
|
|
413
414
|
`Entity: ${n.label} (${n.id})${n.properties ? ' - ' + JSON.stringify(n.properties) : ''}`
|
|
414
415
|
).join('\n');
|
|
415
416
|
context = `GRAPH KNOWLEDGE:\n${graphContext}\n\nVECTOR CONTEXT:\n${context}`;
|
|
@@ -417,7 +418,7 @@ Assistant:
|
|
|
417
418
|
|
|
418
419
|
// 5. Generation (Streaming)
|
|
419
420
|
const messages: ChatMessage[] = [...history, { role: 'user', content: question }];
|
|
420
|
-
|
|
421
|
+
|
|
421
422
|
if (this.llmProvider.chatStream) {
|
|
422
423
|
const stream = this.llmProvider.chatStream(messages, context);
|
|
423
424
|
if (!stream) {
|
|
@@ -449,7 +450,7 @@ Assistant:
|
|
|
449
450
|
|
|
450
451
|
const cacheKey = `${ns}::${query}`;
|
|
451
452
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
452
|
-
|
|
453
|
+
|
|
453
454
|
const [retrievedVector, graphData] = await Promise.all([
|
|
454
455
|
queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: 'query' }),
|
|
455
456
|
this.graphDB && this.config.rag?.useGraphRetrieval
|