@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 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(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
842
- if (match.includes("```")) return match;
841
+ raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
843
842
  if (!looksLikeStructuredPayload(match)) return match;
844
- const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
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(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
805
- if (match.includes("```")) return match;
804
+ raw = raw.replace(/(\{[\s\S]+?\})(?!\s*```)/g, (match) => {
806
805
  if (!looksLikeStructuredPayload(match)) return match;
807
- const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"') ? "ui" : "json";
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",
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
- .replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, '$1\n'); // Remove blank lines between rows
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 ```chart markers.
701
+ // This handles models (like Llama 3.2) that often omit the ```ui markers.
702
702
  if (!isStreaming) {
703
- // Look for objects that look like chart or product data
704
- raw = raw.replace(/(?:^|\n)\s*\{[\s\S]*\}\s*(?:\n|$)/g, (match) => {
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
- const type = match.includes('"view"') || match.includes('"chartType"') || match.includes('"type": "pie"') || match.includes('"type":"pie"') || match.includes('"type": "bar"') || match.includes('"type":"bar"') || match.includes('"type": "line"') || match.includes('"type":"line"')
709
- ? 'ui'
710
- : 'json';
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
- ? 'text-white'
875
- : 'bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80'
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
- ? 'text-white rounded-tr-sm'
887
- : 'bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm'
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})` } : {}
@@ -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