@retrivora-ai/rag-engine 1.6.3 → 1.6.5
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/index.js +6 -3
- package/dist/index.mjs +6 -3
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +20 -17
- package/src/core/Pipeline.ts +8 -8
package/dist/index.js
CHANGED
|
@@ -838,10 +838,13 @@ function MessageBubble({
|
|
|
838
838
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
839
839
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
840
840
|
if (!isStreaming) {
|
|
841
|
-
raw = raw.replace(/(
|
|
842
|
-
if (match.includes("```")) return match;
|
|
841
|
+
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
843
842
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
844
|
-
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";
|
|
845
848
|
return `
|
|
846
849
|
|
|
847
850
|
\`\`\`${type}
|
package/dist/index.mjs
CHANGED
|
@@ -801,10 +801,13 @@ function MessageBubble({
|
|
|
801
801
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
802
802
|
raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
|
|
803
803
|
if (!isStreaming) {
|
|
804
|
-
raw = raw.replace(/(
|
|
805
|
-
if (match.includes("```")) return match;
|
|
804
|
+
raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
|
|
806
805
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
807
|
-
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";
|
|
808
811
|
return `
|
|
809
812
|
|
|
810
813
|
\`\`\`${type}
|
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.5",
|
|
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,
|
|
@@ -692,22 +692,25 @@ export function MessageBubble({
|
|
|
692
692
|
const processedMarkdown = React.useMemo(() => {
|
|
693
693
|
let raw = structuredContent.payload ? structuredContent.text : (cleanContent || message.content);
|
|
694
694
|
const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
|
|
695
|
-
|
|
695
|
+
|
|
696
696
|
// 1. Structural fixes
|
|
697
697
|
raw = raw.replace(/([^\n])\n\|/g, '$1\n\n|') // Ensure blank line before table
|
|
698
|
-
|
|
698
|
+
.replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, '$1\n'); // Remove blank lines between rows
|
|
699
699
|
|
|
700
700
|
// 2. HEALING: Detect naked JSON charts/products and wrap them if markers are missing
|
|
701
|
-
// 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.
|
|
702
702
|
if (!isStreaming) {
|
|
703
|
-
//
|
|
704
|
-
raw = raw.replace(/(
|
|
705
|
-
// Only wrap if not already in a code block
|
|
706
|
-
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) => {
|
|
707
705
|
if (!looksLikeStructuredPayload(match)) return match;
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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';
|
|
711
714
|
return `\n\n\`\`\`${type}\n${match.trim()}\n\`\`\`\n\n`;
|
|
712
715
|
});
|
|
713
716
|
}
|
|
@@ -871,8 +874,8 @@ export function MessageBubble({
|
|
|
871
874
|
{/* Avatar */}
|
|
872
875
|
<div
|
|
873
876
|
className={`flex-shrink-0 ${isCompact ? 'w-7 h-7' : 'w-8 h-8'} rounded-full flex items-center justify-center shadow-lg ${isUser
|
|
874
|
-
|
|
875
|
-
|
|
877
|
+
? 'text-white'
|
|
878
|
+
: 'bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80'
|
|
876
879
|
}`}
|
|
877
880
|
style={isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}}
|
|
878
881
|
>
|
|
@@ -883,8 +886,8 @@ export function MessageBubble({
|
|
|
883
886
|
{/* Bubble */}
|
|
884
887
|
<div
|
|
885
888
|
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
|
|
886
|
-
|
|
887
|
-
|
|
889
|
+
? 'text-white rounded-tr-sm'
|
|
890
|
+
: 'bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm'
|
|
888
891
|
}`}
|
|
889
892
|
style={
|
|
890
893
|
isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -214,7 +214,7 @@ Assistant:
|
|
|
214
214
|
try {
|
|
215
215
|
const chunks = await this.prepareChunks(doc);
|
|
216
216
|
const vectors = await this.processEmbeddings(chunks);
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
const upsertDocs = chunks.map((chunk, i) => ({
|
|
219
219
|
id: chunk.id,
|
|
220
220
|
vector: vectors[i],
|
|
@@ -316,7 +316,7 @@ Assistant:
|
|
|
316
316
|
*/
|
|
317
317
|
private async processGraphIngestion(docId: string | number, chunks: Chunk[]): Promise<void> {
|
|
318
318
|
console.log(`[Pipeline] Extracting entities for doc ${docId} (${chunks.length} chunks)...`);
|
|
319
|
-
|
|
319
|
+
|
|
320
320
|
const extractionOptions: BatchOptions = {
|
|
321
321
|
batchSize: 2, // Low concurrency for LLM extraction
|
|
322
322
|
maxRetries: 1,
|
|
@@ -387,11 +387,11 @@ Assistant:
|
|
|
387
387
|
// 2. Parallel Retrieval
|
|
388
388
|
const hints = QueryProcessor.extractQueryFieldHints(question, this.config.rag?.filterableFields);
|
|
389
389
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
390
|
-
|
|
390
|
+
|
|
391
391
|
console.log(`[Pipeline] 🧩 Extracted filters:`, JSON.stringify(filter));
|
|
392
392
|
|
|
393
|
-
const { sources: rawSources, graphData } = await this.retrieve(searchQuery, {
|
|
394
|
-
namespace: ns,
|
|
393
|
+
const { sources: rawSources, graphData } = await this.retrieve(searchQuery, {
|
|
394
|
+
namespace: ns,
|
|
395
395
|
topK: topK * 2,
|
|
396
396
|
filter
|
|
397
397
|
});
|
|
@@ -410,7 +410,7 @@ Assistant:
|
|
|
410
410
|
: 'No relevant context found.';
|
|
411
411
|
|
|
412
412
|
if (graphData && graphData.nodes.length > 0) {
|
|
413
|
-
const graphContext = graphData.nodes.map(n =>
|
|
413
|
+
const graphContext = graphData.nodes.map(n =>
|
|
414
414
|
`Entity: ${n.label} (${n.id})${n.properties ? ' - ' + JSON.stringify(n.properties) : ''}`
|
|
415
415
|
).join('\n');
|
|
416
416
|
context = `GRAPH KNOWLEDGE:\n${graphContext}\n\nVECTOR CONTEXT:\n${context}`;
|
|
@@ -418,7 +418,7 @@ Assistant:
|
|
|
418
418
|
|
|
419
419
|
// 5. Generation (Streaming)
|
|
420
420
|
const messages: ChatMessage[] = [...history, { role: 'user', content: question }];
|
|
421
|
-
|
|
421
|
+
|
|
422
422
|
if (this.llmProvider.chatStream) {
|
|
423
423
|
const stream = this.llmProvider.chatStream(messages, context);
|
|
424
424
|
if (!stream) {
|
|
@@ -450,7 +450,7 @@ Assistant:
|
|
|
450
450
|
|
|
451
451
|
const cacheKey = `${ns}::${query}`;
|
|
452
452
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
453
|
-
|
|
453
|
+
|
|
454
454
|
const [retrievedVector, graphData] = await Promise.all([
|
|
455
455
|
queryVector ? Promise.resolve(queryVector) : this.embeddingProvider.embed(query, { taskType: 'query' }),
|
|
456
456
|
this.graphDB && this.config.rag?.useGraphRetrieval
|