@retrivora-ai/rag-engine 1.3.1 → 1.3.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/index.mjs CHANGED
@@ -186,6 +186,30 @@ var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#e
186
186
  function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6" }) {
187
187
  const { type, data } = config;
188
188
  const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
189
+ const sanitizedData = React4.useMemo(() => {
190
+ if (!data) return [];
191
+ return data.map((item) => {
192
+ const newItem = {};
193
+ Object.keys(item).forEach((k) => {
194
+ const val = item[k];
195
+ if (Array.isArray(val)) {
196
+ val.forEach((subItem) => {
197
+ if (typeof subItem === "object" && subItem !== null) {
198
+ Object.keys(subItem).forEach((sk) => {
199
+ const subVal = subItem[sk];
200
+ if (typeof subVal !== "object" || subVal === null) {
201
+ newItem[sk] = subVal;
202
+ }
203
+ });
204
+ }
205
+ });
206
+ } else if (typeof val !== "object" || val === null) {
207
+ newItem[k] = val;
208
+ }
209
+ });
210
+ return newItem;
211
+ });
212
+ }, [data]);
189
213
  if (!data || data.length === 0) {
190
214
  return /* @__PURE__ */ React4.createElement("div", { className: "p-4 text-sm text-slate-500" }, "No data available for chart.");
191
215
  }
@@ -201,18 +225,6 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
201
225
  }).slice(0, 5);
202
226
  const finalXKey = String(resolvedXKey);
203
227
  const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
204
- const sanitizedData = React4.useMemo(() => {
205
- return data.map((item) => {
206
- const newItem = {};
207
- Object.keys(item).forEach((k) => {
208
- const val = item[k];
209
- if (typeof val !== "object" || val === null) {
210
- newItem[k] = val;
211
- }
212
- });
213
- return newItem;
214
- });
215
- }, [data]);
216
228
  if (type === "pie") {
217
229
  const pieDataKey = finalDataKeys[0] || "value";
218
230
  return /* @__PURE__ */ React4.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ React4.createElement(ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ React4.createElement(PieChart, null, /* @__PURE__ */ React4.createElement(
@@ -269,6 +281,90 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
269
281
  }
270
282
 
271
283
  // src/components/MessageBubble.tsx
284
+ function sanitizeJson(raw) {
285
+ let s = raw.trim();
286
+ s = s.replace(
287
+ /:\s*(-?\d+(?:\.\d+)?)\s*([+\-*/])\s*(-?\d+(?:\.\d+)?)/g,
288
+ (_, a, op, b) => {
289
+ const n1 = parseFloat(a);
290
+ const n2 = parseFloat(b);
291
+ const result = op === "+" ? n1 + n2 : op === "-" ? n1 - n2 : op === "*" ? n1 * n2 : n2 !== 0 ? n1 / n2 : n1;
292
+ return `: ${result}`;
293
+ }
294
+ );
295
+ s = s.replace(/\/\/[^\n]*/g, "");
296
+ s = s.replace(/([{,]\s*)([A-Za-z_$][A-Za-z0-9_$]*)\s*:/g, '$1"$2":');
297
+ s = s.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"');
298
+ s = s.replace(/,\s*([}\]])/g, "$1");
299
+ s = s.replace(/([{,])\s*""\s*(?=[,}])/g, "$1");
300
+ {
301
+ let inString = false;
302
+ let escape = false;
303
+ let braces = 0;
304
+ let brackets = 0;
305
+ for (const ch of s) {
306
+ if (escape) {
307
+ escape = false;
308
+ continue;
309
+ }
310
+ if (ch === "\\" && inString) {
311
+ escape = true;
312
+ continue;
313
+ }
314
+ if (ch === '"') {
315
+ inString = !inString;
316
+ continue;
317
+ }
318
+ if (inString) continue;
319
+ if (ch === "{") braces++;
320
+ else if (ch === "}") braces--;
321
+ else if (ch === "[") brackets++;
322
+ else if (ch === "]") brackets--;
323
+ }
324
+ if (inString) s += '"';
325
+ while (brackets > 0) {
326
+ s += "]";
327
+ brackets--;
328
+ }
329
+ while (braces > 0) {
330
+ s += "}";
331
+ braces--;
332
+ }
333
+ }
334
+ const lastClose = Math.max(s.lastIndexOf("}"), s.lastIndexOf("]"));
335
+ if (lastClose !== -1 && lastClose < s.length - 1) {
336
+ s = s.substring(0, lastClose + 1);
337
+ }
338
+ return s;
339
+ }
340
+ function resolveImage(data) {
341
+ for (const key of ["image", "img", "thumbnail"]) {
342
+ const v = data[key];
343
+ if (typeof v === "string" && v) return v;
344
+ }
345
+ if (Array.isArray(data.images) && typeof data.images[0] === "string") {
346
+ return data.images[0];
347
+ }
348
+ return void 0;
349
+ }
350
+ function ChartBlock({ rawContent, primaryColor, accentColor }) {
351
+ const result = React5.useMemo(() => {
352
+ if (!rawContent || rawContent === "undefined") return { error: "Empty chart config." };
353
+ try {
354
+ const sanitized = sanitizeJson(rawContent);
355
+ const config = JSON.parse(sanitized);
356
+ return { config };
357
+ } catch (err) {
358
+ const sanitized = sanitizeJson(rawContent);
359
+ console.error("[ChartBlock] Parsing failed.\nError:", err, "\nSanitized:\n", sanitized);
360
+ return { error: String(err) };
361
+ }
362
+ }, [rawContent]);
363
+ if ("error" in result) {
364
+ return /* @__PURE__ */ React5.createElement("div", { className: "p-4 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm border border-red-100 dark:border-red-900/30" }, /* @__PURE__ */ React5.createElement("p", { className: "font-medium mb-1" }, "Failed to render chart"), /* @__PURE__ */ React5.createElement("p", { className: "opacity-70 text-xs" }, "The generated configuration is invalid. Check the console for details."));
365
+ }
366
+ return /* @__PURE__ */ React5.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ React5.createElement(DynamicChart, { config: result.config, primaryColor, accentColor }));
367
+ }
272
368
  function MessageBubble({
273
369
  message,
274
370
  sources,
@@ -279,28 +375,18 @@ function MessageBubble({
279
375
  }) {
280
376
  const isUser = message.role === "user";
281
377
  const [showSources, setShowSources] = React5.useState(false);
282
- const resolveImage = (data) => {
283
- if (!data) return void 0;
284
- const singleFields = ["image", "img", "thumbnail"];
285
- for (const field of singleFields) {
286
- const val = data[field];
287
- if (typeof val === "string" && val) return val;
288
- }
289
- if (Array.isArray(data.images) && data.images.length > 0) {
290
- if (typeof data.images[0] === "string") return data.images[0];
291
- }
292
- return void 0;
293
- };
294
378
  const productsFromSources = React5.useMemo(() => {
295
379
  if (isUser || !sources) return [];
296
380
  return sources.filter((s) => {
297
- const m = s.metadata || {};
381
+ var _a;
382
+ const m = (_a = s.metadata) != null ? _a : {};
298
383
  return m.price || m.image || m.img || m.thumbnail || m.images || m.brand || m.type === "product";
299
384
  }).map((s) => {
300
- const m = s.metadata || {};
385
+ var _a, _b, _c, _d;
386
+ const m = (_a = s.metadata) != null ? _a : {};
301
387
  return {
302
388
  id: s.id,
303
- name: m.name || m.title || s.content.split("\n")[0] || "Unknown Product",
389
+ name: (_d = (_c = (_b = m.name) != null ? _b : m.title) != null ? _c : s.content.split("\n")[0]) != null ? _d : "Unknown Product",
304
390
  brand: m.brand,
305
391
  price: m.price,
306
392
  image: resolveImage(m),
@@ -315,16 +401,19 @@ function MessageBubble({
315
401
  const products = [];
316
402
  let content = message.content;
317
403
  if (content.includes('"type": "products"') || content.includes('"type":"products"')) {
318
- const matches = Array.from(content.matchAll(jsonRegex));
319
- for (const m of matches) {
404
+ for (const match of content.matchAll(jsonRegex)) {
320
405
  try {
321
- const data = JSON.parse(m[1]);
406
+ const data = JSON.parse(match[1]);
322
407
  if (data.type === "products" && Array.isArray(data.items)) {
323
- const formattedItems = data.items.map((item) => __spreadProps(__spreadValues({}, item), {
324
- image: item.image || resolveImage(item)
325
- }));
326
- products.push(...formattedItems);
327
- content = content.replace(m[0], "");
408
+ products.push(
409
+ ...data.items.map((item) => {
410
+ var _a;
411
+ return __spreadProps(__spreadValues({}, item), {
412
+ image: (_a = item.image) != null ? _a : resolveImage(item)
413
+ });
414
+ })
415
+ );
416
+ content = content.replace(match[0], "");
328
417
  }
329
418
  } catch (e) {
330
419
  }
@@ -334,22 +423,82 @@ function MessageBubble({
334
423
  }, [message.content, isUser]);
335
424
  const allProducts = React5.useMemo(() => {
336
425
  if (productsFromContent.length > 0) return productsFromContent;
337
- const uniqueProducts = [];
338
- const seenIds = /* @__PURE__ */ new Set();
426
+ const seen = /* @__PURE__ */ new Set();
339
427
  const contentLower = message.content.toLowerCase();
340
- for (const p of productsFromSources) {
341
- const identifier = p.id || p.name;
342
- if (seenIds.has(identifier)) continue;
343
- const nameMatch = contentLower.includes(p.name.toLowerCase());
344
- const brandMatch = p.brand ? contentLower.includes(p.brand.toLowerCase()) : false;
345
- if (nameMatch || brandMatch) {
346
- seenIds.add(identifier);
347
- uniqueProducts.push(p);
428
+ return productsFromSources.filter((p) => {
429
+ var _a;
430
+ const id = String((_a = p.id) != null ? _a : p.name);
431
+ if (seen.has(id)) return false;
432
+ const mentioned = contentLower.includes(p.name.toLowerCase()) || (p.brand ? contentLower.includes(p.brand.toLowerCase()) : false);
433
+ if (mentioned) {
434
+ seen.add(id);
435
+ return true;
348
436
  }
349
- }
350
- return uniqueProducts;
437
+ return false;
438
+ });
351
439
  }, [productsFromSources, productsFromContent, message.content]);
352
- const hasProducts = allProducts.length > 0;
440
+ const markdownComponents = React5.useMemo(
441
+ () => ({
442
+ table: (_a) => {
443
+ var props = __objRest(_a, []);
444
+ return /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ React5.createElement("table", __spreadValues({ className: "w-full text-left border-collapse min-w-[400px]" }, props)));
445
+ },
446
+ thead: (_b) => {
447
+ var props = __objRest(_b, []);
448
+ return /* @__PURE__ */ React5.createElement(
449
+ "thead",
450
+ __spreadValues({
451
+ className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
452
+ }, props)
453
+ );
454
+ },
455
+ th: (_c) => {
456
+ var _d = _c, { children } = _d, props = __objRest(_d, ["children"]);
457
+ return /* @__PURE__ */ React5.createElement(
458
+ "th",
459
+ __spreadValues({
460
+ className: "p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl"
461
+ }, props),
462
+ normaliseChild(children)
463
+ );
464
+ },
465
+ td: (_e) => {
466
+ var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
467
+ return /* @__PURE__ */ React5.createElement(
468
+ "td",
469
+ __spreadValues({
470
+ className: "p-3 border-b border-slate-100 dark:border-white/5 last:border-0 text-slate-600 dark:text-white/70"
471
+ }, props),
472
+ normaliseChild(children)
473
+ );
474
+ },
475
+ code(_g) {
476
+ var _h = _g, {
477
+ inline,
478
+ className,
479
+ children
480
+ } = _h, props = __objRest(_h, [
481
+ "inline",
482
+ "className",
483
+ "children"
484
+ ]);
485
+ var _a;
486
+ const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
487
+ if (!inline && lang === "chart") {
488
+ return /* @__PURE__ */ React5.createElement(
489
+ ChartBlock,
490
+ {
491
+ rawContent: String(children != null ? children : "").trim(),
492
+ primaryColor,
493
+ accentColor
494
+ }
495
+ );
496
+ }
497
+ return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
498
+ }
499
+ }),
500
+ [primaryColor, accentColor]
501
+ );
353
502
  return /* @__PURE__ */ React5.createElement("div", { className: `flex gap-3 ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ React5.createElement(
354
503
  "div",
355
504
  {
@@ -363,68 +512,8 @@ function MessageBubble({
363
512
  className: `relative px-4 py-3 rounded-2xl text-sm leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "text-white rounded-tr-sm" : "bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm"}`,
364
513
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
365
514
  },
366
- isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(
367
- ReactMarkdown,
368
- {
369
- remarkPlugins: [remarkGfm],
370
- components: {
371
- table: (_a) => {
372
- var props = __objRest(_a, []);
373
- return /* @__PURE__ */ React5.createElement("div", { className: "overflow-x-auto my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ React5.createElement("table", __spreadValues({ className: "w-full text-left border-collapse min-w-[400px]" }, props)));
374
- },
375
- thead: (_b) => {
376
- var props = __objRest(_b, []);
377
- return /* @__PURE__ */ React5.createElement("thead", __spreadValues({ className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, props));
378
- },
379
- th: (_c) => {
380
- var _d = _c, { children } = _d, props = __objRest(_d, ["children"]);
381
- return /* @__PURE__ */ React5.createElement("th", __spreadValues({ className: "p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl" }, props), typeof children === "object" && children !== null && !Array.isArray(children) && !children.$$typeof ? JSON.stringify(children) : children);
382
- },
383
- td: (_e) => {
384
- var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
385
- return /* @__PURE__ */ React5.createElement("td", __spreadValues({ className: "p-3 border-b border-slate-100 dark:border-white/5 last:border-0 text-slate-600 dark:text-white/70" }, props), typeof children === "object" && children !== null && !Array.isArray(children) && !children.$$typeof ? JSON.stringify(children) : children);
386
- },
387
- code(_g) {
388
- var _h = _g, { inline, className, children } = _h, props = __objRest(_h, ["inline", "className", "children"]);
389
- const match = /language-(\w+)/.exec(className || "");
390
- const isChart = match && match[1] === "chart";
391
- if (!inline && isChart) {
392
- const rawContent = String(children || "").trim();
393
- if (!rawContent || rawContent === "undefined") {
394
- return null;
395
- }
396
- const sanitizeJson = (json) => {
397
- return json.replace(/:\s*(\d+(\.\d+)?)\s*([\+\-\*\/])\s*(\d+(\.\d+)?)/g, (_, n1, __, op, n2) => {
398
- var _a;
399
- const v1 = parseFloat(n1);
400
- const v2 = parseFloat(n2);
401
- const ops = { "+": v1 + v2, "-": v1 - v2, "*": v1 * v2, "/": v1 / v2 };
402
- return `: ${(_a = ops[op]) != null ? _a : v1}`;
403
- }).replace(/([{,])\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1 "$2":').replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"').replace(/,\s*([\]}])/g, "$1").replace(/}\s*{/g, "},{").replace(/]\s*\[/g, "],[").replace(/\/\/.*$/gm, "").replace(/([{,])\s*""\s*([,}])/g, "$1$2");
404
- };
405
- try {
406
- const sanitized = sanitizeJson(rawContent);
407
- const config = JSON.parse(sanitized);
408
- return /* @__PURE__ */ React5.createElement("div", { className: "my-4 p-4 bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm" }, /* @__PURE__ */ React5.createElement(
409
- DynamicChart,
410
- {
411
- config,
412
- primaryColor,
413
- accentColor
414
- }
415
- ));
416
- } catch (err) {
417
- console.error("[MessageBubble] Chart parsing failed:", err, "\nSanitized content:", sanitizeJson(rawContent));
418
- return /* @__PURE__ */ React5.createElement("div", { className: "p-4 bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 rounded-lg text-sm border border-red-100 dark:border-red-900/30" }, /* @__PURE__ */ React5.createElement("p", { className: "font-medium mb-1" }, "Failed to render chart"), /* @__PURE__ */ React5.createElement("p", { className: "opacity-70 text-xs" }, "The generated configuration is invalid. Check console for details."));
419
- }
420
- }
421
- return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
422
- }
423
- }
424
- },
425
- cleanContent || message.content
426
- ), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
427
- ), !isUser && hasProducts && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
515
+ isStreaming && !message.content ? /* @__PURE__ */ React5.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ React5.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ React5.createElement("div", { className: `prose prose-sm max-w-none ${isUser ? "prose-invert" : "dark:prose-invert"}` }, /* @__PURE__ */ React5.createElement(ReactMarkdown, { remarkPlugins: [remarkGfm], components: markdownComponents }, cleanContent || message.content), isStreaming && message.content && /* @__PURE__ */ React5.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
516
+ ), !isUser && allProducts.length > 0 && /* @__PURE__ */ React5.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ React5.createElement(
428
517
  ProductCarousel,
429
518
  {
430
519
  products: allProducts,
@@ -444,6 +533,12 @@ function MessageBubble({
444
533
  " used"
445
534
  ), showSources && /* @__PURE__ */ React5.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ React5.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
446
535
  }
536
+ function normaliseChild(children) {
537
+ if (typeof children === "object" && children !== null && !Array.isArray(children) && !React5.isValidElement(children)) {
538
+ return JSON.stringify(children);
539
+ }
540
+ return children;
541
+ }
447
542
 
448
543
  // src/components/ConfigProvider.tsx
449
544
  import React6, { createContext, useContext } from "react";
package/dist/server.js CHANGED
@@ -3357,7 +3357,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
3357
3357
  1. Use ONLY valid JSON (double quotes, no trailing commas).
3358
3358
  2. NO math expressions (e.g., use 100, NOT 50+50).
3359
3359
  3. dataKeys MUST exactly match the property names in the data objects.
3360
- 4. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
3360
+ 4. data objects MUST be FLAT (no nested objects or arrays).
3361
+ 5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
3361
3362
  \`\`\`chart
3362
3363
  {
3363
3364
  "type": "bar" | "line" | "pie",
@@ -3919,7 +3920,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
3919
3920
  1. Use ONLY valid JSON (double quotes, no trailing commas).
3920
3921
  2. NO math expressions (e.g., use 100, NOT 50+50).
3921
3922
  3. dataKeys MUST exactly match the property names in the data objects.
3922
- 4. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
3923
+ 4. data objects MUST be FLAT (no nested objects or arrays).
3924
+ 5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
3923
3925
  \`\`\`chart
3924
3926
  {
3925
3927
  "type": "bar" | "line" | "pie",
package/dist/server.mjs CHANGED
@@ -39,7 +39,7 @@ import {
39
39
  sseFrame,
40
40
  sseMetaFrame,
41
41
  sseTextFrame
42
- } from "./chunk-AYOQ4LF4.mjs";
42
+ } from "./chunk-FQ7OYZLF.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.3.1",
3
+ "version": "1.3.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",
@@ -26,6 +26,35 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
26
26
  const { type, data } = config;
27
27
  const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
28
28
 
29
+ // CRITICAL: Sanitize the data array to remove any non-primitive values (objects/arrays)
30
+ // This prevents the "Objects are not valid as a React child" error in Tooltips/Legends
31
+ // This hook MUST be called before any early returns to satisfy React rules
32
+ const sanitizedData = React.useMemo(() => {
33
+ if (!data) return [];
34
+ return data.map(item => {
35
+ const newItem: Record<string, string | number | null> = {};
36
+ Object.keys(item).forEach(k => {
37
+ const val = item[k];
38
+ if (Array.isArray(val)) {
39
+ // If the LLM output nested arrays, attempt to flatten them
40
+ val.forEach(subItem => {
41
+ if (typeof subItem === 'object' && subItem !== null) {
42
+ Object.keys(subItem).forEach(sk => {
43
+ const subVal = (subItem as Record<string, unknown>)[sk];
44
+ if (typeof subVal !== 'object' || subVal === null) {
45
+ newItem[sk] = subVal as string | number | null;
46
+ }
47
+ });
48
+ }
49
+ });
50
+ } else if (typeof val !== 'object' || val === null) {
51
+ newItem[k] = val as string | number | null;
52
+ }
53
+ });
54
+ return newItem;
55
+ });
56
+ }, [data]);
57
+
29
58
  if (!data || data.length === 0) {
30
59
  return <div className="p-4 text-sm text-slate-500">No data available for chart.</div>;
31
60
  }
@@ -58,21 +87,6 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
58
87
  const finalXKey = String(resolvedXKey);
59
88
  const finalDataKeys = resolvedDataKeys.map(String).filter(k => k !== 'undefined');
60
89
 
61
- // CRITICAL: Sanitize the data array to remove any non-primitive values (objects/arrays)
62
- // This prevents the "Objects are not valid as a React child" error in Tooltips/Legends
63
- const sanitizedData = React.useMemo(() => {
64
- return data.map(item => {
65
- const newItem: Record<string, any> = {};
66
- Object.keys(item).forEach(k => {
67
- const val = item[k];
68
- if (typeof val !== 'object' || val === null) {
69
- newItem[k] = val;
70
- }
71
- });
72
- return newItem;
73
- });
74
- }, [data]);
75
-
76
90
  // Handle Pie Chart separately as it has a different structure
77
91
  if (type === 'pie') {
78
92
  const pieDataKey = finalDataKeys[0] || 'value';