@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/{chunk-AYOQ4LF4.mjs → chunk-FQ7OYZLF.mjs} +4 -2
- package/dist/handlers/index.js +4 -2
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.js +205 -110
- package/dist/index.mjs +205 -110
- package/dist/server.js +4 -2
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/DynamicChart.tsx +29 -15
- package/src/components/MessageBubble.tsx +246 -160
- package/src/core/LangChainAgent.ts +2 -1
- package/src/core/Pipeline.ts +2 -1
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
319
|
-
for (const m of matches) {
|
|
404
|
+
for (const match of content.matchAll(jsonRegex)) {
|
|
320
405
|
try {
|
|
321
|
-
const data = JSON.parse(
|
|
406
|
+
const data = JSON.parse(match[1]);
|
|
322
407
|
if (data.type === "products" && Array.isArray(data.items)) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
|
338
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
426
|
+
const seen = /* @__PURE__ */ new Set();
|
|
339
427
|
const contentLower = message.content.toLowerCase();
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
if (
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
437
|
+
return false;
|
|
438
|
+
});
|
|
351
439
|
}, [productsFromSources, productsFromContent, message.content]);
|
|
352
|
-
const
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.3.
|
|
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';
|