@retrivora-ai/rag-engine 1.5.0 → 1.5.2

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.
@@ -2259,22 +2259,17 @@ var Pipeline = class {
2259
2259
  async initialize() {
2260
2260
  var _a, _b;
2261
2261
  if (this.initialised) return;
2262
- const CHART_MARKER = "<!-- VIZ_PROTOCOL_V1 -->";
2262
+ const CHART_MARKER = "<!-- VIZ_PROTOCOL_V2 -->";
2263
2263
  const chartInstruction = `
2264
2264
 
2265
2265
  ${CHART_MARKER}
2266
- ### MANDATORY CHART PROTOCOL:
2267
- If asked for a chart (pie, bar, line), you MUST output exactly ONE block using this structure:
2268
- \`\`\`chart
2269
- {
2270
- "type": "pie",
2271
- "data": [ { "label": "Item A", "value": 10 }, { "label": "Item B", "value": 20 } ]
2272
- }
2273
- \`\`\`
2274
- - RULES:
2275
- 1. You MUST include the \`\`\`chart and \`\`\` markers. Naked JSON will NOT render.
2276
- 2. Output ONLY the chart block. No Python snippets. No "here is the data" text.
2277
- 3. Data objects MUST be FLAT. No math (e.g. use 10, NOT 5+5).`;
2266
+ ### MANDATORY VISUALIZATION RULES:
2267
+ - If asked for statistics, distribution, or comparisons: You MUST use the \`\`\`chart block.
2268
+ - FORMAT: \`\`\`chart { "type": "pie" | "bar" | "line", "data": [ { "label": "X", "value": 10 } ] } \`\`\`
2269
+ - RULES:
2270
+ 1. ALWAYS include the \`\`\`chart and \`\`\` markers.
2271
+ 2. NEVER use text, tables, or ASCII art for charts.
2272
+ 3. Output ONLY the chart block. No Python, no text descriptions.`;
2278
2273
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
2279
2274
  this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
2280
2275
  }
@@ -3822,22 +3822,17 @@ var Pipeline = class {
3822
3822
  async initialize() {
3823
3823
  var _a, _b;
3824
3824
  if (this.initialised) return;
3825
- const CHART_MARKER = "<!-- VIZ_PROTOCOL_V1 -->";
3825
+ const CHART_MARKER = "<!-- VIZ_PROTOCOL_V2 -->";
3826
3826
  const chartInstruction = `
3827
3827
 
3828
3828
  ${CHART_MARKER}
3829
- ### MANDATORY CHART PROTOCOL:
3830
- If asked for a chart (pie, bar, line), you MUST output exactly ONE block using this structure:
3831
- \`\`\`chart
3832
- {
3833
- "type": "pie",
3834
- "data": [ { "label": "Item A", "value": 10 }, { "label": "Item B", "value": 20 } ]
3835
- }
3836
- \`\`\`
3837
- - RULES:
3838
- 1. You MUST include the \`\`\`chart and \`\`\` markers. Naked JSON will NOT render.
3839
- 2. Output ONLY the chart block. No Python snippets. No "here is the data" text.
3840
- 3. Data objects MUST be FLAT. No math (e.g. use 10, NOT 5+5).`;
3829
+ ### MANDATORY VISUALIZATION RULES:
3830
+ - If asked for statistics, distribution, or comparisons: You MUST use the \`\`\`chart block.
3831
+ - FORMAT: \`\`\`chart { "type": "pie" | "bar" | "line", "data": [ { "label": "X", "value": 10 } ] } \`\`\`
3832
+ - RULES:
3833
+ 1. ALWAYS include the \`\`\`chart and \`\`\` markers.
3834
+ 2. NEVER use text, tables, or ASCII art for charts.
3835
+ 3. Output ONLY the chart block. No Python, no text descriptions.`;
3841
3836
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
3842
3837
  this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
3843
3838
  }
@@ -9,7 +9,7 @@ import {
9
9
  sseFrame,
10
10
  sseMetaFrame,
11
11
  sseTextFrame
12
- } from "../chunk-YTL3SLQU.mjs";
12
+ } from "../chunk-C4UPQX3E.mjs";
13
13
  import "../chunk-YLTMFW4M.mjs";
14
14
  import "../chunk-X4TOT24V.mjs";
15
15
  export {
package/dist/index.js CHANGED
@@ -503,13 +503,8 @@ function MessageBubble({
503
503
  };
504
504
  });
505
505
  }, [sources, isUser]);
506
- const isVisualizationRequested = import_react5.default.useMemo(() => {
507
- if (isUser) return false;
508
- const text = message.content.toLowerCase();
509
- return message.content.includes("```chart") || text.includes("pie chart") || text.includes("bar chart") || text.includes("line chart") || text.includes("distribution across");
510
- }, [message.content, isUser]);
511
506
  const { productsFromContent, cleanContent } = import_react5.default.useMemo(() => {
512
- if (isUser || isVisualizationRequested) {
507
+ if (isUser) {
513
508
  return { productsFromContent: [], cleanContent: message.content };
514
509
  }
515
510
  const jsonRegex = /```json\s*([\s\S]*?)\s*```/g;
@@ -535,7 +530,7 @@ function MessageBubble({
535
530
  }
536
531
  }
537
532
  return { productsFromContent: products, cleanContent: content.trim() };
538
- }, [message.content, isUser, isVisualizationRequested]);
533
+ }, [message.content, isUser]);
539
534
  const allProducts = import_react5.default.useMemo(() => {
540
535
  if (productsFromContent.length > 0) return productsFromContent;
541
536
  const seen = /* @__PURE__ */ new Set();
@@ -555,6 +550,19 @@ function MessageBubble({
555
550
  const processedMarkdown = import_react5.default.useMemo(() => {
556
551
  let raw = cleanContent || message.content;
557
552
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
553
+ if (!isStreaming) {
554
+ raw = raw.replace(/(?:^|\n)\s*\{\s*[\s\S]*?"type":\s*"(?:pie|bar|line|products)"[\s\S]*?\}\s*(?:\n|$)/g, (match) => {
555
+ if (match.includes("```")) return match;
556
+ const type = match.includes('"products"') ? "json" : "chart";
557
+ return `
558
+
559
+ \`\`\`${type}
560
+ ${match.trim()}
561
+ \`\`\`
562
+
563
+ `;
564
+ });
565
+ }
558
566
  if (isStreaming) {
559
567
  raw = raw.replace(/((?:^|\n)\|.*)+/g, (match) => {
560
568
  return `
package/dist/index.mjs CHANGED
@@ -466,13 +466,8 @@ function MessageBubble({
466
466
  };
467
467
  });
468
468
  }, [sources, isUser]);
469
- const isVisualizationRequested = React5.useMemo(() => {
470
- if (isUser) return false;
471
- const text = message.content.toLowerCase();
472
- return message.content.includes("```chart") || text.includes("pie chart") || text.includes("bar chart") || text.includes("line chart") || text.includes("distribution across");
473
- }, [message.content, isUser]);
474
469
  const { productsFromContent, cleanContent } = React5.useMemo(() => {
475
- if (isUser || isVisualizationRequested) {
470
+ if (isUser) {
476
471
  return { productsFromContent: [], cleanContent: message.content };
477
472
  }
478
473
  const jsonRegex = /```json\s*([\s\S]*?)\s*```/g;
@@ -498,7 +493,7 @@ function MessageBubble({
498
493
  }
499
494
  }
500
495
  return { productsFromContent: products, cleanContent: content.trim() };
501
- }, [message.content, isUser, isVisualizationRequested]);
496
+ }, [message.content, isUser]);
502
497
  const allProducts = React5.useMemo(() => {
503
498
  if (productsFromContent.length > 0) return productsFromContent;
504
499
  const seen = /* @__PURE__ */ new Set();
@@ -518,6 +513,19 @@ function MessageBubble({
518
513
  const processedMarkdown = React5.useMemo(() => {
519
514
  let raw = cleanContent || message.content;
520
515
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
516
+ if (!isStreaming) {
517
+ raw = raw.replace(/(?:^|\n)\s*\{\s*[\s\S]*?"type":\s*"(?:pie|bar|line|products)"[\s\S]*?\}\s*(?:\n|$)/g, (match) => {
518
+ if (match.includes("```")) return match;
519
+ const type = match.includes('"products"') ? "json" : "chart";
520
+ return `
521
+
522
+ \`\`\`${type}
523
+ ${match.trim()}
524
+ \`\`\`
525
+
526
+ `;
527
+ });
528
+ }
521
529
  if (isStreaming) {
522
530
  raw = raw.replace(/((?:^|\n)\|.*)+/g, (match) => {
523
531
  return `
package/dist/server.js CHANGED
@@ -3913,22 +3913,17 @@ var Pipeline = class {
3913
3913
  async initialize() {
3914
3914
  var _a, _b;
3915
3915
  if (this.initialised) return;
3916
- const CHART_MARKER = "<!-- VIZ_PROTOCOL_V1 -->";
3916
+ const CHART_MARKER = "<!-- VIZ_PROTOCOL_V2 -->";
3917
3917
  const chartInstruction = `
3918
3918
 
3919
3919
  ${CHART_MARKER}
3920
- ### MANDATORY CHART PROTOCOL:
3921
- If asked for a chart (pie, bar, line), you MUST output exactly ONE block using this structure:
3922
- \`\`\`chart
3923
- {
3924
- "type": "pie",
3925
- "data": [ { "label": "Item A", "value": 10 }, { "label": "Item B", "value": 20 } ]
3926
- }
3927
- \`\`\`
3928
- - RULES:
3929
- 1. You MUST include the \`\`\`chart and \`\`\` markers. Naked JSON will NOT render.
3930
- 2. Output ONLY the chart block. No Python snippets. No "here is the data" text.
3931
- 3. Data objects MUST be FLAT. No math (e.g. use 10, NOT 5+5).`;
3920
+ ### MANDATORY VISUALIZATION RULES:
3921
+ - If asked for statistics, distribution, or comparisons: You MUST use the \`\`\`chart block.
3922
+ - FORMAT: \`\`\`chart { "type": "pie" | "bar" | "line", "data": [ { "label": "X", "value": 10 } ] } \`\`\`
3923
+ - RULES:
3924
+ 1. ALWAYS include the \`\`\`chart and \`\`\` markers.
3925
+ 2. NEVER use text, tables, or ASCII art for charts.
3926
+ 3. Output ONLY the chart block. No Python, no text descriptions.`;
3932
3927
  if (!((_a = this.config.llm.systemPrompt) == null ? void 0 : _a.includes(CHART_MARKER))) {
3933
3928
  this.config.llm.systemPrompt = (this.config.llm.systemPrompt || "") + chartInstruction;
3934
3929
  }
package/dist/server.mjs CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  sseFrame,
40
40
  sseMetaFrame,
41
41
  sseTextFrame
42
- } from "./chunk-YTL3SLQU.mjs";
42
+ } from "./chunk-C4UPQX3E.mjs";
43
43
  import "./chunk-YLTMFW4M.mjs";
44
44
  import {
45
45
  PineconeProvider
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retrivora-ai/rag-engine",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
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",
@@ -309,23 +309,9 @@ export function MessageBubble({
309
309
  });
310
310
  }, [sources, isUser]);
311
311
 
312
- // ── Visualization Intent Detection ────────────────────────────────────────
313
- // Robust detection to prevent UI clutter and ensure atomic rendering.
314
- const isVisualizationRequested = React.useMemo(() => {
315
- if (isUser) return false;
316
- const text = message.content.toLowerCase();
317
- return (
318
- message.content.includes('```chart') ||
319
- text.includes('pie chart') ||
320
- text.includes('bar chart') ||
321
- text.includes('line chart') ||
322
- text.includes('distribution across')
323
- );
324
- }, [message.content, isUser]);
325
-
326
312
  // ── Products + cleaned content from structured JSON blocks in the message ──
327
313
  const { productsFromContent, cleanContent } = React.useMemo(() => {
328
- if (isUser || isVisualizationRequested) {
314
+ if (isUser) {
329
315
  return { productsFromContent: [] as Product[], cleanContent: message.content };
330
316
  }
331
317
 
@@ -353,7 +339,7 @@ export function MessageBubble({
353
339
  }
354
340
 
355
341
  return { productsFromContent: products, cleanContent: content.trim() };
356
- }, [message.content, isUser, isVisualizationRequested]);
342
+ }, [message.content, isUser]);
357
343
 
358
344
  // ── Merge & deduplicate products ───────────────────────────────────────────
359
345
  const allProducts = React.useMemo<Product[]>(() => {
@@ -380,7 +366,19 @@ export function MessageBubble({
380
366
  raw = raw.replace(/([^\n])\n\|/g, '$1\n\n|') // Ensure blank line before table
381
367
  .replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, '$1\n'); // Remove blank lines between rows
382
368
 
383
- // 2. HIJACKING: If streaming, hide table-like content to prevent raw markdown flashing.
369
+ // 2. HEALING: Detect naked JSON charts/products and wrap them if markers are missing
370
+ // This handles models (like Llama 3.2) that often omit the ```chart markers.
371
+ if (!isStreaming) {
372
+ // Look for objects that look like chart or product data
373
+ raw = raw.replace(/(?:^|\n)\s*\{\s*[\s\S]*?"type":\s*"(?:pie|bar|line|products)"[\s\S]*?\}\s*(?:\n|$)/g, (match) => {
374
+ // Only wrap if not already in a code block
375
+ if (match.includes('```')) return match;
376
+ const type = match.includes('"products"') ? 'json' : 'chart';
377
+ return `\n\n\`\`\`${type}\n${match.trim()}\n\`\`\`\n\n`;
378
+ });
379
+ }
380
+
381
+ // 3. HIJACKING: If streaming, hide table-like content to prevent raw markdown flashing.
384
382
  if (isStreaming) {
385
383
  raw = raw.replace(/((?:^|\n)\|.*)+/g, (match) => {
386
384
  return `\n\n\`\`\`table-loading\n${match.trim()}\n\`\`\`\n\n`;
@@ -101,20 +101,15 @@ 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 = '<!-- VIZ_PROTOCOL_V1 -->';
104
+ const CHART_MARKER = '<!-- VIZ_PROTOCOL_V2 -->';
105
105
  const chartInstruction = `\n\n${CHART_MARKER}
106
- ### MANDATORY CHART PROTOCOL:
107
- If asked for a chart (pie, bar, line), you MUST output exactly ONE block using this structure:
108
- \`\`\`chart
109
- {
110
- "type": "pie",
111
- "data": [ { "label": "Item A", "value": 10 }, { "label": "Item B", "value": 20 } ]
112
- }
113
- \`\`\`
114
- - RULES:
115
- 1. You MUST include the \`\`\`chart and \`\`\` markers. Naked JSON will NOT render.
116
- 2. Output ONLY the chart block. No Python snippets. No "here is the data" text.
117
- 3. Data objects MUST be FLAT. No math (e.g. use 10, NOT 5+5).`;
106
+ ### MANDATORY VISUALIZATION RULES:
107
+ - If asked for statistics, distribution, or comparisons: You MUST use the \`\`\`chart block.
108
+ - FORMAT: \`\`\`chart { "type": "pie" | "bar" | "line", "data": [ { "label": "X", "value": 10 } ] } \`\`\`
109
+ - RULES:
110
+ 1. ALWAYS include the \`\`\`chart and \`\`\` markers.
111
+ 2. NEVER use text, tables, or ASCII art for charts.
112
+ 3. Output ONLY the chart block. No Python, no text descriptions.`;
118
113
 
119
114
  if (!this.config.llm.systemPrompt?.includes(CHART_MARKER)) {
120
115
  this.config.llm.systemPrompt = (this.config.llm.systemPrompt || '') + chartInstruction;