@retrivora-ai/rag-engine 1.3.0 → 1.3.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.
- 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 +61 -27
- package/dist/index.mjs +61 -27
- package/dist/server.js +4 -2
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/DynamicChart.tsx +50 -15
- package/src/components/MessageBubble.tsx +30 -27
- package/src/core/LangChainAgent.ts +2 -1
- package/src/core/Pipeline.ts +2 -1
|
@@ -1703,7 +1703,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
|
|
|
1703
1703
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
1704
1704
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
1705
1705
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
1706
|
-
4.
|
|
1706
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
1707
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
1707
1708
|
\`\`\`chart
|
|
1708
1709
|
{
|
|
1709
1710
|
"type": "bar" | "line" | "pie",
|
|
@@ -2265,7 +2266,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
|
|
|
2265
2266
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
2266
2267
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
2267
2268
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
2268
|
-
4.
|
|
2269
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
2270
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
2269
2271
|
\`\`\`chart
|
|
2270
2272
|
{
|
|
2271
2273
|
"type": "bar" | "line" | "pie",
|
package/dist/handlers/index.js
CHANGED
|
@@ -3272,7 +3272,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
|
|
|
3272
3272
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
3273
3273
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
3274
3274
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
3275
|
-
4.
|
|
3275
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
3276
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
3276
3277
|
\`\`\`chart
|
|
3277
3278
|
{
|
|
3278
3279
|
"type": "bar" | "line" | "pie",
|
|
@@ -3828,7 +3829,8 @@ When presenting structured data, statistics, or comparisons, decide if it is bes
|
|
|
3828
3829
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
3829
3830
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
3830
3831
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
3831
|
-
4.
|
|
3832
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
3833
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
3832
3834
|
\`\`\`chart
|
|
3833
3835
|
{
|
|
3834
3836
|
"type": "bar" | "line" | "pie",
|
package/dist/handlers/index.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -223,24 +223,53 @@ var DEFAULT_COLORS = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#e
|
|
|
223
223
|
function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6" }) {
|
|
224
224
|
const { type, data } = config;
|
|
225
225
|
const colors = config.colors || [primaryColor, accentColor, ...DEFAULT_COLORS];
|
|
226
|
+
const sanitizedData = import_react4.default.useMemo(() => {
|
|
227
|
+
if (!data) return [];
|
|
228
|
+
return data.map((item) => {
|
|
229
|
+
const newItem = {};
|
|
230
|
+
Object.keys(item).forEach((k) => {
|
|
231
|
+
const val = item[k];
|
|
232
|
+
if (Array.isArray(val)) {
|
|
233
|
+
val.forEach((subItem) => {
|
|
234
|
+
if (typeof subItem === "object" && subItem !== null) {
|
|
235
|
+
Object.keys(subItem).forEach((sk) => {
|
|
236
|
+
const subVal = subItem[sk];
|
|
237
|
+
if (typeof subVal !== "object" || subVal === null) {
|
|
238
|
+
newItem[sk] = subVal;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
} else if (typeof val !== "object" || val === null) {
|
|
244
|
+
newItem[k] = val;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
return newItem;
|
|
248
|
+
});
|
|
249
|
+
}, [data]);
|
|
226
250
|
if (!data || data.length === 0) {
|
|
227
251
|
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "p-4 text-sm text-slate-500" }, "No data available for chart.");
|
|
228
252
|
}
|
|
229
253
|
const firstItem = data[0];
|
|
230
254
|
const allKeys = Object.keys(firstItem);
|
|
231
255
|
const resolvedXKey = config.xAxisKey && firstItem[config.xAxisKey] !== void 0 ? config.xAxisKey : allKeys.find((k) => k.toLowerCase() === "name" || k.toLowerCase() === "label" || k.toLowerCase() === "category") || allKeys.find((k) => typeof firstItem[k] === "string") || allKeys[0];
|
|
232
|
-
const resolvedDataKeys = config.dataKeys && config.dataKeys.every((k) =>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
256
|
+
const resolvedDataKeys = config.dataKeys && config.dataKeys.every((k) => {
|
|
257
|
+
const val = firstItem[k];
|
|
258
|
+
return val !== void 0 && typeof val !== "object";
|
|
259
|
+
}) ? config.dataKeys : allKeys.filter((k) => {
|
|
260
|
+
const val = firstItem[k];
|
|
261
|
+
return k !== resolvedXKey && (typeof val === "number" || k.toLowerCase() === "value" || k.toLowerCase() === "count");
|
|
262
|
+
}).slice(0, 5);
|
|
263
|
+
const finalXKey = String(resolvedXKey);
|
|
264
|
+
const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
|
|
236
265
|
if (type === "pie") {
|
|
237
|
-
const pieDataKey =
|
|
266
|
+
const pieDataKey = finalDataKeys[0] || "value";
|
|
238
267
|
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.PieChart, null, /* @__PURE__ */ import_react4.default.createElement(
|
|
239
268
|
import_recharts.Pie,
|
|
240
269
|
{
|
|
241
|
-
data,
|
|
270
|
+
data: sanitizedData,
|
|
242
271
|
dataKey: pieDataKey,
|
|
243
|
-
nameKey:
|
|
272
|
+
nameKey: finalXKey,
|
|
244
273
|
cx: "50%",
|
|
245
274
|
cy: "50%",
|
|
246
275
|
outerRadius: 80,
|
|
@@ -254,13 +283,13 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
254
283
|
}
|
|
255
284
|
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, null))));
|
|
256
285
|
}
|
|
257
|
-
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey:
|
|
286
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "99%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
|
|
258
287
|
import_recharts.Tooltip,
|
|
259
288
|
{
|
|
260
289
|
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
|
|
261
290
|
cursor: { fill: "#f1f5f9" }
|
|
262
291
|
}
|
|
263
|
-
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
292
|
+
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
264
293
|
import_recharts.Bar,
|
|
265
294
|
{
|
|
266
295
|
key,
|
|
@@ -269,12 +298,12 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
269
298
|
radius: [4, 4, 0, 0],
|
|
270
299
|
barSize: Math.max(20, 60 / data.length)
|
|
271
300
|
}
|
|
272
|
-
))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey:
|
|
301
|
+
))) : /* @__PURE__ */ import_react4.default.createElement(import_recharts.LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(
|
|
273
302
|
import_recharts.Tooltip,
|
|
274
303
|
{
|
|
275
304
|
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
276
305
|
}
|
|
277
|
-
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
306
|
+
), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
|
|
278
307
|
import_recharts.Line,
|
|
279
308
|
{
|
|
280
309
|
key,
|
|
@@ -397,15 +426,15 @@ function MessageBubble({
|
|
|
397
426
|
return /* @__PURE__ */ import_react5.default.createElement("thead", __spreadValues({ className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, props));
|
|
398
427
|
},
|
|
399
428
|
th: (_c) => {
|
|
400
|
-
var props = __objRest(
|
|
401
|
-
return /* @__PURE__ */ import_react5.default.createElement("th", __spreadValues({ className: "p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl" }, props));
|
|
429
|
+
var _d = _c, { children } = _d, props = __objRest(_d, ["children"]);
|
|
430
|
+
return /* @__PURE__ */ import_react5.default.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) && !import_react5.default.isValidElement(children) ? JSON.stringify(children) : children);
|
|
402
431
|
},
|
|
403
|
-
td: (
|
|
404
|
-
var props = __objRest(
|
|
405
|
-
return /* @__PURE__ */ import_react5.default.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));
|
|
432
|
+
td: (_e) => {
|
|
433
|
+
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
434
|
+
return /* @__PURE__ */ import_react5.default.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) && !import_react5.default.isValidElement(children) ? JSON.stringify(children) : children);
|
|
406
435
|
},
|
|
407
|
-
code(
|
|
408
|
-
var
|
|
436
|
+
code(_g) {
|
|
437
|
+
var _h = _g, { inline, className, children } = _h, props = __objRest(_h, ["inline", "className", "children"]);
|
|
409
438
|
const match = /language-(\w+)/.exec(className || "");
|
|
410
439
|
const isChart = match && match[1] === "chart";
|
|
411
440
|
if (!inline && isChart) {
|
|
@@ -414,16 +443,21 @@ function MessageBubble({
|
|
|
414
443
|
return null;
|
|
415
444
|
}
|
|
416
445
|
const sanitizeJson = (json) => {
|
|
417
|
-
|
|
446
|
+
const firstBrace = json.indexOf("{");
|
|
447
|
+
const firstBracket = json.indexOf("[");
|
|
448
|
+
const start = firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket) ? firstBrace : firstBracket;
|
|
449
|
+
const lastBrace = json.lastIndexOf("}");
|
|
450
|
+
const lastBracket = json.lastIndexOf("]");
|
|
451
|
+
const end = Math.max(lastBrace, lastBracket);
|
|
452
|
+
if (start === -1 || end === -1 || end < start) return json;
|
|
453
|
+
const trimmed = json.substring(start, end + 1);
|
|
454
|
+
return trimmed.replace(/:\s*(\d+(\.\d+)?)\s*([\+\-\*\/])\s*(\d+(\.\d+)?)/g, (_, n1, __, op, n2) => {
|
|
455
|
+
var _a;
|
|
418
456
|
const v1 = parseFloat(n1);
|
|
419
457
|
const v2 = parseFloat(n2);
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
if (op === "*") res = v1 * v2;
|
|
424
|
-
if (op === "/") res = v1 / v2;
|
|
425
|
-
return `: ${res}`;
|
|
426
|
-
}).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, ",").replace(/\{\s*""\s*,/g, "{").replace(/,\s*""\s*\}/g, "}");
|
|
458
|
+
const ops = { "+": v1 + v2, "-": v1 - v2, "*": v1 * v2, "/": v1 / v2 };
|
|
459
|
+
return `: ${(_a = ops[op]) != null ? _a : v1}`;
|
|
460
|
+
}).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");
|
|
427
461
|
};
|
|
428
462
|
try {
|
|
429
463
|
const sanitized = sanitizeJson(rawContent);
|
|
@@ -441,7 +475,7 @@ function MessageBubble({
|
|
|
441
475
|
return /* @__PURE__ */ import_react5.default.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__ */ import_react5.default.createElement("p", { className: "font-medium mb-1" }, "Failed to render chart"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "opacity-70 text-xs" }, "The generated configuration is invalid. Check console for details."));
|
|
442
476
|
}
|
|
443
477
|
}
|
|
444
|
-
return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), children);
|
|
478
|
+
return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
445
479
|
}
|
|
446
480
|
}
|
|
447
481
|
},
|
package/dist/index.mjs
CHANGED
|
@@ -186,24 +186,53 @@ 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
|
}
|
|
192
216
|
const firstItem = data[0];
|
|
193
217
|
const allKeys = Object.keys(firstItem);
|
|
194
218
|
const resolvedXKey = config.xAxisKey && firstItem[config.xAxisKey] !== void 0 ? config.xAxisKey : allKeys.find((k) => k.toLowerCase() === "name" || k.toLowerCase() === "label" || k.toLowerCase() === "category") || allKeys.find((k) => typeof firstItem[k] === "string") || allKeys[0];
|
|
195
|
-
const resolvedDataKeys = config.dataKeys && config.dataKeys.every((k) =>
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
219
|
+
const resolvedDataKeys = config.dataKeys && config.dataKeys.every((k) => {
|
|
220
|
+
const val = firstItem[k];
|
|
221
|
+
return val !== void 0 && typeof val !== "object";
|
|
222
|
+
}) ? config.dataKeys : allKeys.filter((k) => {
|
|
223
|
+
const val = firstItem[k];
|
|
224
|
+
return k !== resolvedXKey && (typeof val === "number" || k.toLowerCase() === "value" || k.toLowerCase() === "count");
|
|
225
|
+
}).slice(0, 5);
|
|
226
|
+
const finalXKey = String(resolvedXKey);
|
|
227
|
+
const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
|
|
199
228
|
if (type === "pie") {
|
|
200
|
-
const pieDataKey =
|
|
229
|
+
const pieDataKey = finalDataKeys[0] || "value";
|
|
201
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(
|
|
202
231
|
Pie,
|
|
203
232
|
{
|
|
204
|
-
data,
|
|
233
|
+
data: sanitizedData,
|
|
205
234
|
dataKey: pieDataKey,
|
|
206
|
-
nameKey:
|
|
235
|
+
nameKey: finalXKey,
|
|
207
236
|
cx: "50%",
|
|
208
237
|
cy: "50%",
|
|
209
238
|
outerRadius: 80,
|
|
@@ -217,13 +246,13 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
217
246
|
}
|
|
218
247
|
), /* @__PURE__ */ React4.createElement(Legend, null))));
|
|
219
248
|
}
|
|
220
|
-
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%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey:
|
|
249
|
+
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%" }, type === "bar" ? /* @__PURE__ */ React4.createElement(BarChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(
|
|
221
250
|
Tooltip,
|
|
222
251
|
{
|
|
223
252
|
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" },
|
|
224
253
|
cursor: { fill: "#f1f5f9" }
|
|
225
254
|
}
|
|
226
|
-
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
255
|
+
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
227
256
|
Bar,
|
|
228
257
|
{
|
|
229
258
|
key,
|
|
@@ -232,12 +261,12 @@ function DynamicChart({ config, primaryColor = "#6366f1", accentColor = "#8b5cf6
|
|
|
232
261
|
radius: [4, 4, 0, 0],
|
|
233
262
|
barSize: Math.max(20, 60 / data.length)
|
|
234
263
|
}
|
|
235
|
-
))) : /* @__PURE__ */ React4.createElement(LineChart, { data, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey:
|
|
264
|
+
))) : /* @__PURE__ */ React4.createElement(LineChart, { data: sanitizedData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ React4.createElement(CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ React4.createElement(XAxis, { dataKey: finalXKey, tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: { stroke: "#cbd5e1" } }), /* @__PURE__ */ React4.createElement(YAxis, { tick: { fontSize: 12, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ React4.createElement(
|
|
236
265
|
Tooltip,
|
|
237
266
|
{
|
|
238
267
|
contentStyle: { borderRadius: "8px", border: "none", boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1)" }
|
|
239
268
|
}
|
|
240
|
-
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }),
|
|
269
|
+
), /* @__PURE__ */ React4.createElement(Legend, { wrapperStyle: { fontSize: 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ React4.createElement(
|
|
241
270
|
Line,
|
|
242
271
|
{
|
|
243
272
|
key,
|
|
@@ -360,15 +389,15 @@ function MessageBubble({
|
|
|
360
389
|
return /* @__PURE__ */ React5.createElement("thead", __spreadValues({ className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, props));
|
|
361
390
|
},
|
|
362
391
|
th: (_c) => {
|
|
363
|
-
var props = __objRest(
|
|
364
|
-
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));
|
|
392
|
+
var _d = _c, { children } = _d, props = __objRest(_d, ["children"]);
|
|
393
|
+
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) && !React5.isValidElement(children) ? JSON.stringify(children) : children);
|
|
365
394
|
},
|
|
366
|
-
td: (
|
|
367
|
-
var props = __objRest(
|
|
368
|
-
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));
|
|
395
|
+
td: (_e) => {
|
|
396
|
+
var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
|
|
397
|
+
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) && !React5.isValidElement(children) ? JSON.stringify(children) : children);
|
|
369
398
|
},
|
|
370
|
-
code(
|
|
371
|
-
var
|
|
399
|
+
code(_g) {
|
|
400
|
+
var _h = _g, { inline, className, children } = _h, props = __objRest(_h, ["inline", "className", "children"]);
|
|
372
401
|
const match = /language-(\w+)/.exec(className || "");
|
|
373
402
|
const isChart = match && match[1] === "chart";
|
|
374
403
|
if (!inline && isChart) {
|
|
@@ -377,16 +406,21 @@ function MessageBubble({
|
|
|
377
406
|
return null;
|
|
378
407
|
}
|
|
379
408
|
const sanitizeJson = (json) => {
|
|
380
|
-
|
|
409
|
+
const firstBrace = json.indexOf("{");
|
|
410
|
+
const firstBracket = json.indexOf("[");
|
|
411
|
+
const start = firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket) ? firstBrace : firstBracket;
|
|
412
|
+
const lastBrace = json.lastIndexOf("}");
|
|
413
|
+
const lastBracket = json.lastIndexOf("]");
|
|
414
|
+
const end = Math.max(lastBrace, lastBracket);
|
|
415
|
+
if (start === -1 || end === -1 || end < start) return json;
|
|
416
|
+
const trimmed = json.substring(start, end + 1);
|
|
417
|
+
return trimmed.replace(/:\s*(\d+(\.\d+)?)\s*([\+\-\*\/])\s*(\d+(\.\d+)?)/g, (_, n1, __, op, n2) => {
|
|
418
|
+
var _a;
|
|
381
419
|
const v1 = parseFloat(n1);
|
|
382
420
|
const v2 = parseFloat(n2);
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
if (op === "*") res = v1 * v2;
|
|
387
|
-
if (op === "/") res = v1 / v2;
|
|
388
|
-
return `: ${res}`;
|
|
389
|
-
}).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, ",").replace(/\{\s*""\s*,/g, "{").replace(/,\s*""\s*\}/g, "}");
|
|
421
|
+
const ops = { "+": v1 + v2, "-": v1 - v2, "*": v1 * v2, "/": v1 / v2 };
|
|
422
|
+
return `: ${(_a = ops[op]) != null ? _a : v1}`;
|
|
423
|
+
}).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");
|
|
390
424
|
};
|
|
391
425
|
try {
|
|
392
426
|
const sanitized = sanitizeJson(rawContent);
|
|
@@ -404,7 +438,7 @@ function MessageBubble({
|
|
|
404
438
|
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."));
|
|
405
439
|
}
|
|
406
440
|
}
|
|
407
|
-
return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), children);
|
|
441
|
+
return /* @__PURE__ */ React5.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
|
|
408
442
|
}
|
|
409
443
|
}
|
|
410
444
|
},
|
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.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",
|
|
@@ -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
|
}
|
|
@@ -42,28 +71,34 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
42
71
|
|| allKeys[0];
|
|
43
72
|
|
|
44
73
|
// Resolve dataKeys: use provided, fallback to 'value', 'count', 'amount', or all numeric keys
|
|
45
|
-
|
|
74
|
+
// CRITICAL: Filter out any keys that point to objects/arrays to prevent React render errors
|
|
75
|
+
const resolvedDataKeys = config.dataKeys && config.dataKeys.every(k => {
|
|
76
|
+
const val = firstItem[k];
|
|
77
|
+
return val !== undefined && typeof val !== 'object';
|
|
78
|
+
})
|
|
46
79
|
? config.dataKeys
|
|
47
|
-
: allKeys.filter(k =>
|
|
80
|
+
: allKeys.filter(k => {
|
|
81
|
+
const val = firstItem[k];
|
|
82
|
+
return k !== resolvedXKey && (typeof val === 'number' || k.toLowerCase() === 'value' || k.toLowerCase() === 'count');
|
|
83
|
+
})
|
|
48
84
|
.slice(0, 5); // Limit to 5 series for sanity
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
86
|
+
// Final sanity check: ensure all keys are strings
|
|
87
|
+
const finalXKey = String(resolvedXKey);
|
|
88
|
+
const finalDataKeys = resolvedDataKeys.map(String).filter(k => k !== 'undefined');
|
|
54
89
|
|
|
55
90
|
// Handle Pie Chart separately as it has a different structure
|
|
56
91
|
if (type === 'pie') {
|
|
57
|
-
const pieDataKey =
|
|
92
|
+
const pieDataKey = finalDataKeys[0] || 'value';
|
|
58
93
|
|
|
59
94
|
return (
|
|
60
95
|
<div className="w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden">
|
|
61
96
|
<ResponsiveContainer width="99%" height="100%">
|
|
62
97
|
<PieChart>
|
|
63
98
|
<Pie
|
|
64
|
-
data={
|
|
99
|
+
data={sanitizedData}
|
|
65
100
|
dataKey={pieDataKey}
|
|
66
|
-
nameKey={
|
|
101
|
+
nameKey={finalXKey}
|
|
67
102
|
cx="50%"
|
|
68
103
|
cy="50%"
|
|
69
104
|
outerRadius={80}
|
|
@@ -88,16 +123,16 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
88
123
|
<div className="w-full h-72 min-h-[280px] mt-4 mb-2 select-none overflow-hidden">
|
|
89
124
|
<ResponsiveContainer width="99%" height="100%">
|
|
90
125
|
{type === 'bar' ? (
|
|
91
|
-
<BarChart data={
|
|
126
|
+
<BarChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
|
92
127
|
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
|
|
93
|
-
<XAxis dataKey={
|
|
128
|
+
<XAxis dataKey={finalXKey} tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
|
|
94
129
|
<YAxis tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={false} />
|
|
95
130
|
<Tooltip
|
|
96
131
|
contentStyle={{ borderRadius: '8px', border: 'none', boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)' }}
|
|
97
132
|
cursor={{ fill: '#f1f5f9' }}
|
|
98
133
|
/>
|
|
99
134
|
<Legend wrapperStyle={{ fontSize: 12 }} />
|
|
100
|
-
{
|
|
135
|
+
{finalDataKeys.map((key, index) => (
|
|
101
136
|
<Bar
|
|
102
137
|
key={key}
|
|
103
138
|
dataKey={key}
|
|
@@ -108,15 +143,15 @@ export function DynamicChart({ config, primaryColor = '#6366f1', accentColor = '
|
|
|
108
143
|
))}
|
|
109
144
|
</BarChart>
|
|
110
145
|
) : (
|
|
111
|
-
<LineChart data={
|
|
146
|
+
<LineChart data={sanitizedData} margin={{ top: 10, right: 10, left: -20, bottom: 0 }}>
|
|
112
147
|
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#e2e8f0" />
|
|
113
|
-
<XAxis dataKey={
|
|
148
|
+
<XAxis dataKey={finalXKey} tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={{ stroke: '#cbd5e1' }} />
|
|
114
149
|
<YAxis tick={{ fontSize: 12, fill: '#64748b' }} tickLine={false} axisLine={false} />
|
|
115
150
|
<Tooltip
|
|
116
151
|
contentStyle={{ borderRadius: '8px', border: 'none', boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)' }}
|
|
117
152
|
/>
|
|
118
153
|
<Legend wrapperStyle={{ fontSize: 12 }} />
|
|
119
|
-
{
|
|
154
|
+
{finalDataKeys.map((key, index) => (
|
|
120
155
|
<Line
|
|
121
156
|
key={key}
|
|
122
157
|
type="monotone"
|
|
@@ -167,11 +167,15 @@ export function MessageBubble({
|
|
|
167
167
|
thead: ({...props}) => (
|
|
168
168
|
<thead className="bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" {...props} />
|
|
169
169
|
),
|
|
170
|
-
th: ({...props}) => (
|
|
171
|
-
<th className="p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl" {...props}
|
|
170
|
+
th: ({children, ...props}) => (
|
|
171
|
+
<th className="p-3 font-semibold text-slate-700 dark:text-white/90 first:rounded-tl-xl last:rounded-tr-xl" {...props}>
|
|
172
|
+
{typeof children === 'object' && children !== null && !Array.isArray(children) && !React.isValidElement(children) ? JSON.stringify(children) : children}
|
|
173
|
+
</th>
|
|
172
174
|
),
|
|
173
|
-
td: ({...props}) => (
|
|
174
|
-
<td className="p-3 border-b border-slate-100 dark:border-white/5 last:border-0 text-slate-600 dark:text-white/70" {...props}
|
|
175
|
+
td: ({children, ...props}) => (
|
|
176
|
+
<td className="p-3 border-b border-slate-100 dark:border-white/5 last:border-0 text-slate-600 dark:text-white/70" {...props}>
|
|
177
|
+
{typeof children === 'object' && children !== null && !Array.isArray(children) && !React.isValidElement(children) ? JSON.stringify(children) : children}
|
|
178
|
+
</td>
|
|
175
179
|
),
|
|
176
180
|
code({ inline, className, children, ...props }: React.HTMLAttributes<HTMLElement> & { inline?: boolean }) {
|
|
177
181
|
const match = /language-(\w+)/.exec(className || '');
|
|
@@ -184,38 +188,37 @@ export function MessageBubble({
|
|
|
184
188
|
return null;
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
//
|
|
191
|
+
// Optimized sanitization helper to handle LLM quirks
|
|
188
192
|
const sanitizeJson = (json: string) => {
|
|
189
|
-
|
|
193
|
+
// 0. Boundary detection: find the actual JSON object/array start/end
|
|
194
|
+
// This removes stray backticks or text the LLM might have included
|
|
195
|
+
const firstBrace = json.indexOf('{');
|
|
196
|
+
const firstBracket = json.indexOf('[');
|
|
197
|
+
const start = (firstBrace !== -1 && (firstBracket === -1 || firstBrace < firstBracket)) ? firstBrace : firstBracket;
|
|
198
|
+
const lastBrace = json.lastIndexOf('}');
|
|
199
|
+
const lastBracket = json.lastIndexOf(']');
|
|
200
|
+
const end = Math.max(lastBrace, lastBracket);
|
|
201
|
+
|
|
202
|
+
if (start === -1 || end === -1 || end < start) return json;
|
|
203
|
+
const trimmed = json.substring(start, end + 1);
|
|
204
|
+
|
|
205
|
+
return trimmed
|
|
190
206
|
// 1. Resolve arithmetic: "value": 495 / 1000 => "value": 0.495
|
|
191
|
-
// Matches : number op number
|
|
192
207
|
.replace(/:\s*(\d+(\.\d+)?)\s*([\+\-\*\/])\s*(\d+(\.\d+)?)/g, (_, n1, __, op, n2) => {
|
|
193
|
-
const v1 = parseFloat(n1);
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
if (op === '+') res = v1 + v2;
|
|
197
|
-
if (op === '-') res = v1 - v2;
|
|
198
|
-
if (op === '*') res = v1 * v2;
|
|
199
|
-
if (op === '/') res = v1 / v2;
|
|
200
|
-
return `: ${res}`;
|
|
208
|
+
const v1 = parseFloat(n1); const v2 = parseFloat(n2);
|
|
209
|
+
const ops: Record<string, number> = { '+': v1 + v2, '-': v1 - v2, '*': v1 * v2, '/': v1 / v2 };
|
|
210
|
+
return `: ${ops[op] ?? v1}`;
|
|
201
211
|
})
|
|
202
|
-
// 2. Quote unquoted keys
|
|
203
|
-
// Matches a word followed by a colon, but not inside a string
|
|
212
|
+
// 2. Quote unquoted keys and fix single quotes
|
|
204
213
|
.replace(/([{,])\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1 "$2":')
|
|
205
|
-
// 3. Convert single quotes to double quotes (for delimiters)
|
|
206
|
-
// This is a heuristic that replaces ' with " when it looks like a JSON string
|
|
207
214
|
.replace(/'([^'\\]*(?:\\.[^'\\]*)*)'/g, '"$1"')
|
|
208
|
-
//
|
|
215
|
+
// 3. Syntax cleanup: trailing/missing commas and comments
|
|
209
216
|
.replace(/,\s*([\]}])/g, '$1')
|
|
210
|
-
// 5. Fix missing commas between objects: {}{ } => {},{ }
|
|
211
217
|
.replace(/}\s*{/g, '},{')
|
|
212
218
|
.replace(/]\s*\[/g, '],[')
|
|
213
|
-
// 6. Remove JS-style comments: // something
|
|
214
219
|
.replace(/\/\/.*$/gm, '')
|
|
215
|
-
//
|
|
216
|
-
.replace(
|
|
217
|
-
.replace(/\{\s*""\s*,/g, '{')
|
|
218
|
-
.replace(/,\s*""\s*\}/g, '}');
|
|
220
|
+
// 4. Remove dangling empty strings
|
|
221
|
+
.replace(/([{,])\s*""\s*([,}])/g, '$1$2');
|
|
219
222
|
};
|
|
220
223
|
|
|
221
224
|
try {
|
|
@@ -242,7 +245,7 @@ export function MessageBubble({
|
|
|
242
245
|
}
|
|
243
246
|
return (
|
|
244
247
|
<code className={className} {...props}>
|
|
245
|
-
{children}
|
|
248
|
+
{typeof children === 'string' || typeof children === 'number' ? children : JSON.stringify(children)}
|
|
246
249
|
</code>
|
|
247
250
|
);
|
|
248
251
|
}
|
|
@@ -57,7 +57,8 @@ export class LangChainAgent {
|
|
|
57
57
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
58
58
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
59
59
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
60
|
-
4.
|
|
60
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
61
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
61
62
|
\`\`\`chart
|
|
62
63
|
{
|
|
63
64
|
"type": "bar" | "line" | "pie",
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -107,7 +107,8 @@ export class Pipeline {
|
|
|
107
107
|
1. Use ONLY valid JSON (double quotes, no trailing commas).
|
|
108
108
|
2. NO math expressions (e.g., use 100, NOT 50+50).
|
|
109
109
|
3. dataKeys MUST exactly match the property names in the data objects.
|
|
110
|
-
4.
|
|
110
|
+
4. data objects MUST be FLAT (no nested objects or arrays).
|
|
111
|
+
5. DO NOT output naked JSON; it MUST be wrapped in \`\`\`chart ... \`\`\`.
|
|
111
112
|
\`\`\`chart
|
|
112
113
|
{
|
|
113
114
|
"type": "bar" | "line" | "pie",
|