@retrivora-ai/rag-engine 1.7.9 → 1.8.1

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.
Files changed (47) hide show
  1. package/dist/DocumentChunker-Dh9TvmGG.d.mts +45 -0
  2. package/dist/DocumentChunker-Dh9TvmGG.d.ts +45 -0
  3. package/dist/{index-wCRqMtdX.d.mts → ILLMProvider-BfRgI1Xh.d.mts} +59 -1
  4. package/dist/{index-wCRqMtdX.d.ts → ILLMProvider-BfRgI1Xh.d.ts} +59 -1
  5. package/dist/MultiTablePostgresProvider-YY7LPNJK.mjs +8 -0
  6. package/dist/{chunk-UHGYLTTY.mjs → chunk-BFYLQYQU.mjs} +846 -458
  7. package/dist/chunk-R3RGUMHE.mjs +218 -0
  8. package/dist/handlers/index.d.mts +2 -2
  9. package/dist/handlers/index.d.ts +2 -2
  10. package/dist/handlers/index.js +1033 -622
  11. package/dist/handlers/index.mjs +1 -1
  12. package/dist/{index-BDqz2_Yu.d.ts → index-1Z4GuYBi.d.ts} +7 -1
  13. package/dist/{index-DhsG2o5q.d.mts → index-BV0z5mb6.d.mts} +7 -1
  14. package/dist/index.d.mts +3 -3
  15. package/dist/index.d.ts +3 -3
  16. package/dist/index.js +507 -352
  17. package/dist/index.mjs +427 -253
  18. package/dist/server.d.mts +35 -5
  19. package/dist/server.d.ts +35 -5
  20. package/dist/server.js +1183 -795
  21. package/dist/server.mjs +163 -176
  22. package/package.json +4 -2
  23. package/src/app/page.tsx +1 -2
  24. package/src/components/DynamicChart.tsx +10 -35
  25. package/src/components/MessageBubble.tsx +223 -74
  26. package/src/components/ProductCard.tsx +2 -2
  27. package/src/components/VisualizationRenderer.tsx +347 -247
  28. package/src/config/RagConfig.ts +5 -0
  29. package/src/config/serverConfig.ts +3 -1
  30. package/src/core/Pipeline.ts +70 -209
  31. package/src/core/ProviderRegistry.ts +2 -2
  32. package/src/core/VectorPlugin.ts +9 -0
  33. package/src/handlers/index.ts +23 -7
  34. package/src/hooks/useRagChat.ts +2 -2
  35. package/src/llm/LLMFactory.ts +54 -2
  36. package/src/llm/providers/AnthropicProvider.ts +12 -8
  37. package/src/llm/providers/GeminiProvider.ts +188 -143
  38. package/src/llm/providers/OllamaProvider.ts +7 -3
  39. package/src/llm/providers/OpenAIProvider.ts +12 -8
  40. package/src/types/chat.ts +6 -0
  41. package/src/types/index.ts +81 -0
  42. package/src/utils/SchemaMapper.ts +129 -0
  43. package/src/utils/UITransformer.ts +524 -194
  44. package/dist/DocumentChunker-Bmscbh-X.d.ts +0 -93
  45. package/dist/DocumentChunker-DCuxrOdM.d.mts +0 -93
  46. package/dist/PostgreSQLProvider-BMOETDZA.mjs +0 -8
  47. package/dist/chunk-FLOSGE6A.mjs +0 -202
package/dist/index.js CHANGED
@@ -71,18 +71,17 @@ __export(index_exports, {
71
71
  module.exports = __toCommonJS(index_exports);
72
72
 
73
73
  // src/components/ChatWidget.tsx
74
- var import_react9 = __toESM(require("react"));
74
+ var import_react10 = __toESM(require("react"));
75
75
  var import_lucide_react6 = require("lucide-react");
76
76
 
77
77
  // src/components/ChatWindow.tsx
78
- var import_react8 = __toESM(require("react"));
78
+ var import_react9 = __toESM(require("react"));
79
79
  var import_lucide_react5 = require("lucide-react");
80
80
 
81
81
  // src/components/MessageBubble.tsx
82
- var import_react5 = __toESM(require("react"));
82
+ var import_react6 = __toESM(require("react"));
83
83
  var import_lucide_react4 = require("lucide-react");
84
84
  var import_react_markdown = __toESM(require("react-markdown"));
85
- var import_remark_gfm = __toESM(require("remark-gfm"));
86
85
 
87
86
  // src/components/SourceCard.tsx
88
87
  var import_react = __toESM(require("react"));
@@ -304,37 +303,12 @@ function DynamicChart({
304
303
  const finalXKey = String(resolvedXKey);
305
304
  const finalDataKeys = resolvedDataKeys.map(String).filter((k) => k !== "undefined");
306
305
  const pieDataKey = finalDataKeys[0] || "value";
307
- const stockAwareColor = (entry, index) => {
308
- var _a, _b, _c;
309
- const stockStatus = String(
310
- (_c = (_b = (_a = entry.stockStatus) != null ? _a : entry.status) != null ? _b : entry.availability) != null ? _c : ""
311
- ).toLowerCase();
312
- const inStockCount = typeof entry.inStockCount === "number" ? entry.inStockCount : void 0;
313
- const outOfStockCount = typeof entry.outOfStockCount === "number" ? entry.outOfStockCount : void 0;
314
- const inStockFlag = entry.inStock;
315
- if (stockStatus.includes("in stock")) return "#10b981";
316
- if (stockStatus.includes("out of stock")) return "#f97316";
317
- if (typeof inStockFlag === "string" && inStockFlag.toLowerCase() === "true") return "#10b981";
318
- if (inStockFlag === 1) return "#10b981";
319
- if (inStockFlag === 0) return "#f97316";
320
- if (typeof inStockCount === "number" || typeof outOfStockCount === "number") {
321
- const inCount = inStockCount != null ? inStockCount : 0;
322
- const outCount = outOfStockCount != null ? outOfStockCount : 0;
323
- if (inCount > outCount) return "#10b981";
324
- if (outCount > inCount) return "#f97316";
325
- }
326
- return colors[index % colors.length];
327
- };
328
306
  const tooltipLabelMap = {
329
- value: "Value",
307
+ value: "Total Items",
330
308
  count: "Count",
331
- inStock: "In stock",
332
- inStockCount: "In stock",
333
- outOfStockCount: "Out of stock",
334
- stockStatus: "Stock status",
335
- category: "Category",
336
- label: "Label",
337
- name: "Name"
309
+ inStockCount: "In Stock",
310
+ outOfStockCount: "Out of Stock",
311
+ stockStatus: "Status"
338
312
  };
339
313
  const renderTooltip = (row, label) => {
340
314
  var _a, _b;
@@ -343,6 +317,8 @@ function DynamicChart({
343
317
  var _a2;
344
318
  if (value === null || value === void 0 || key === finalXKey) return null;
345
319
  if (typeof value === "object") return null;
320
+ const forbiddenKeys = ["fill", "color", "payload", "percent", "stroke", "inStock"];
321
+ if (forbiddenKeys.includes(key)) return null;
346
322
  return /* @__PURE__ */ import_react4.default.createElement("div", { key, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react4.default.createElement("span", null, (_a2 = tooltipLabelMap[key]) != null ? _a2 : key), /* @__PURE__ */ import_react4.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, String(value)));
347
323
  }));
348
324
  };
@@ -367,7 +343,7 @@ function DynamicChart({
367
343
  label: false,
368
344
  labelLine: false
369
345
  },
370
- sanitizedData.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: stockAwareColor(entry, index) }))
346
+ sanitizedData.map((_entry, index) => /* @__PURE__ */ import_react4.default.createElement(import_recharts.Cell, { key: `cell-${index}`, fill: colors[index % colors.length] }))
371
347
  ), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0) }), showLegend && !isCompact && /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" })))));
372
348
  }
373
349
  return /* @__PURE__ */ import_react4.default.createElement("div", { ref: containerRef, className: "w-full min-w-0 mt-4 mb-2 select-none overflow-hidden" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "w-full aspect-[4/3]" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, type === "bar" ? /* @__PURE__ */ import_react4.default.createElement(import_recharts.BarChart, { data: sanitizedData, margin: chartMargin }, /* @__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: axisTick, tickFormatter: truncateAxisLabel, tickLine: false, axisLine: { stroke: "#cbd5e1" }, interval: 0, minTickGap: isTiny ? 2 : isCompact ? 6 : 12 }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.YAxis, { tick: axisTick, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react4.default.createElement(import_recharts.Tooltip, { content: (props) => renderTooltip(getTooltipRow(props.payload), typeof props.label === "string" ? props.label : void 0), cursor: { fill: "#f1f5f9" } }), showLegend && /* @__PURE__ */ import_react4.default.createElement(import_recharts.Legend, { wrapperStyle: { fontSize: isCompact ? 10 : 12 } }), finalDataKeys.map((key, index) => /* @__PURE__ */ import_react4.default.createElement(
@@ -394,175 +370,232 @@ function DynamicChart({
394
370
  }
395
371
 
396
372
  // src/components/VisualizationRenderer.tsx
397
- var import_image2 = __toESM(require("next/image"));
373
+ var import_react5 = __toESM(require("react"));
374
+ var import_recharts2 = require("recharts");
375
+ var CHART_COLORS = [
376
+ "#6366f1",
377
+ // indigo
378
+ "#10b981",
379
+ // emerald
380
+ "#f59e0b",
381
+ // amber
382
+ "#ef4444",
383
+ // red
384
+ "#8b5cf6",
385
+ // purple
386
+ "#ec4899",
387
+ // pink
388
+ "#06b6d4",
389
+ // cyan
390
+ "#f97316"
391
+ // orange
392
+ ];
393
+ function getColor(index) {
394
+ return CHART_COLORS[index % CHART_COLORS.length];
395
+ }
396
+ function CustomTooltip({
397
+ active,
398
+ payload,
399
+ label
400
+ }) {
401
+ if (!active || !payload || payload.length === 0) return null;
402
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "rounded-xl border border-slate-200 bg-white px-3 py-2 text-xs shadow-xl dark:border-white/10 dark:bg-slate-950" }, label && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mb-2 font-semibold text-slate-800 dark:text-white/90" }, label), payload.map((entry, i) => /* @__PURE__ */ import_react5.default.createElement("div", { key: i, className: "flex items-center justify-between gap-3 text-slate-600 dark:text-white/70" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1.5" }, entry.color && /* @__PURE__ */ import_react5.default.createElement(
403
+ "span",
404
+ {
405
+ className: "inline-block w-2 h-2 rounded-full flex-shrink-0",
406
+ style: { background: entry.color }
407
+ }
408
+ ), entry.name), /* @__PURE__ */ import_react5.default.createElement("span", { className: "font-medium text-slate-900 dark:text-white/90" }, entry.value))));
409
+ }
398
410
  function VisualizationRenderer({
399
411
  data,
400
- className = ""
412
+ className = "",
413
+ primaryColor,
414
+ onAddToCart
401
415
  }) {
416
+ var _a;
402
417
  if (!data) {
403
- return /* @__PURE__ */ React.createElement("div", { className: `p-4 text-gray-500 ${className}` }, "No data available for visualization");
418
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: `p-4 text-gray-500 ${className}` }, "No data available for visualization");
404
419
  }
405
- return /* @__PURE__ */ React.createElement("div", { className: `space-y-4 ${className}` }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white" }, data.title), data.description && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400" }, data.description)), renderVisualization(data.type, data.data));
420
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: `space-y-4 ${className}` }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "text-sm font-semibold text-slate-900 dark:text-white" }, data.title), data.description && data.description !== ((_a = data.data) == null ? void 0 : _a.content) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 dark:text-slate-400" }, data.description)), renderVisualization(data.type, data.data, onAddToCart, primaryColor));
406
421
  }
407
- function renderVisualization(type, data) {
408
- switch (type) {
409
- case "pie_chart":
410
- return renderPieChart(data);
411
- case "bar_chart":
412
- return renderBarChart(data);
413
- case "line_chart":
414
- return renderLineChart(data);
415
- case "table":
416
- return renderTable(data);
417
- case "product_carousel":
418
- return renderProductCarousel(data);
419
- case "text":
420
- default:
421
- return renderText(data);
422
+ function renderVisualization(type, data, onAddToCart, primaryColor) {
423
+ try {
424
+ switch (type) {
425
+ case "pie_chart":
426
+ return /* @__PURE__ */ import_react5.default.createElement(PieChartView, { data });
427
+ case "bar_chart":
428
+ return /* @__PURE__ */ import_react5.default.createElement(BarChartView, { data, primaryColor });
429
+ case "line_chart":
430
+ return /* @__PURE__ */ import_react5.default.createElement(LineChartView, { data, primaryColor });
431
+ case "radar_chart":
432
+ return /* @__PURE__ */ import_react5.default.createElement(RadarChartView, { data });
433
+ case "table":
434
+ return /* @__PURE__ */ import_react5.default.createElement(TableView, { data });
435
+ case "product_carousel":
436
+ case "carousel":
437
+ return /* @__PURE__ */ import_react5.default.createElement(CarouselView, { data, onAddToCart, primaryColor });
438
+ case "text":
439
+ default:
440
+ return /* @__PURE__ */ import_react5.default.createElement(TextView, { data });
441
+ }
442
+ } catch (error) {
443
+ console.warn("[VisualizationRenderer] Rendering failed, falling back to text:", error);
444
+ return /* @__PURE__ */ import_react5.default.createElement(TextView, { data: { content: "Unable to render the requested visualization." } });
422
445
  }
423
446
  }
424
- function renderPieChart(data) {
425
- if (!Array.isArray(data)) {
426
- return /* @__PURE__ */ React.createElement("div", { className: "text-red-500" }, "Invalid pie chart data");
447
+ function PieChartView({ data }) {
448
+ if (!Array.isArray(data) || data.length === 0) {
449
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid pie chart data");
427
450
  }
428
- return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 p-4 rounded-lg shadow" }, /* @__PURE__ */ React.createElement("div", { className: "flex flex-wrap gap-2" }, data.map((item, idx) => /* @__PURE__ */ React.createElement(
429
- "div",
451
+ const chartData = data.map((item) => ({
452
+ name: item.label,
453
+ value: item.value
454
+ }));
455
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 280 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PieChart, null, /* @__PURE__ */ import_react5.default.createElement(
456
+ import_recharts2.Pie,
430
457
  {
431
- key: idx,
432
- className: "flex items-center gap-2 p-2 bg-gray-50 dark:bg-gray-700 rounded"
458
+ data: chartData,
459
+ dataKey: "value",
460
+ nameKey: "name",
461
+ cx: "50%",
462
+ cy: "50%",
463
+ outerRadius: "68%",
464
+ label: false,
465
+ labelLine: false
433
466
  },
434
- /* @__PURE__ */ React.createElement(
435
- "div",
436
- {
437
- className: "w-3 h-3 rounded-full",
438
- style: { backgroundColor: generateColor(idx) }
439
- }
440
- ),
441
- /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300" }, item.label, ": ", item.value),
442
- item.inStock !== void 0 && /* @__PURE__ */ React.createElement(
443
- "span",
444
- {
445
- className: `text-xs px-2 py-1 rounded ${item.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
446
- },
447
- item.inStock ? "In Stock" : "Out of Stock"
448
- )
449
- ))));
467
+ chartData.map((_entry, index) => /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Cell, { key: `cell-${index}`, fill: getColor(index) }))
468
+ ), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 }, verticalAlign: "bottom" }))));
450
469
  }
451
- function renderBarChart(data) {
452
- if (!Array.isArray(data)) {
453
- return /* @__PURE__ */ React.createElement("div", { className: "text-red-500" }, "Invalid bar chart data");
470
+ function BarChartView({ data, primaryColor }) {
471
+ if (!Array.isArray(data) || data.length === 0) {
472
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid bar chart data");
454
473
  }
455
- return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 p-4 rounded-lg shadow overflow-x-auto" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-3" }, data.map((item, idx) => /* @__PURE__ */ React.createElement("div", { key: idx, className: "space-y-1" }, /* @__PURE__ */ React.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300" }, item.category), /* @__PURE__ */ React.createElement("span", { className: "text-sm text-gray-600 dark:text-gray-400" }, item.value)), /* @__PURE__ */ React.createElement("div", { className: "w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2" }, /* @__PURE__ */ React.createElement(
456
- "div",
474
+ const chartData = data.map((item) => __spreadValues(__spreadValues({
475
+ category: item.category,
476
+ value: item.value
477
+ }, item.inStockCount !== void 0 && { inStockCount: item.inStockCount }), item.outOfStockCount !== void 0 && { outOfStockCount: item.outOfStockCount }));
478
+ const barColor = primaryColor != null ? primaryColor : getColor(0);
479
+ const hasStock = chartData.some((d) => "inStockCount" in d);
480
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.BarChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(
481
+ import_recharts2.XAxis,
457
482
  {
458
- className: "h-full rounded-full transition-all",
459
- style: {
460
- width: `${item.value / Math.max(...data.map((d) => d.value)) * 100}%`,
461
- backgroundColor: generateColor(idx)
462
- }
483
+ dataKey: "category",
484
+ tick: { fontSize: 11, fill: "#64748b" },
485
+ tickLine: false,
486
+ axisLine: { stroke: "#cbd5e1" }
463
487
  }
464
- )), item.inStock !== void 0 && /* @__PURE__ */ React.createElement(
465
- "span",
466
- {
467
- className: `text-xs px-2 py-1 rounded inline-block ${item.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
468
- },
469
- item.inStock ? "In Stock" : "Out of Stock"
470
- )))));
488
+ ), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null), cursor: { fill: "#f1f5f9" } }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }), hasStock ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "inStockCount", name: "In Stock", fill: getColor(1), radius: [4, 4, 0, 0] }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "outOfStockCount", name: "Out of Stock", fill: getColor(3), radius: [4, 4, 0, 0] })) : /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Bar, { dataKey: "value", name: "Value", fill: barColor, radius: [4, 4, 0, 0] }))));
471
489
  }
472
- function renderLineChart(data) {
473
- if (!Array.isArray(data)) {
474
- return /* @__PURE__ */ React.createElement("div", { className: "text-red-500" }, "Invalid line chart data");
490
+ function LineChartView({ data, primaryColor }) {
491
+ if (!Array.isArray(data) || data.length === 0) {
492
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid line chart data");
475
493
  }
476
- return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 p-4 rounded-lg shadow overflow-x-auto" }, /* @__PURE__ */ React.createElement("div", { className: "space-y-2" }, data.map((point, idx) => /* @__PURE__ */ React.createElement(
477
- "div",
494
+ const chartData = data.map((point) => {
495
+ var _a;
496
+ return {
497
+ label: String((_a = point.label) != null ? _a : point.timestamp),
498
+ value: Number(point.value)
499
+ };
500
+ });
501
+ const lineColor = primaryColor != null ? primaryColor : getColor(0);
502
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 260 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.LineChart, { data: chartData, margin: { top: 10, right: 10, left: -20, bottom: 0 } }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", vertical: false, stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(
503
+ import_recharts2.XAxis,
478
504
  {
479
- key: idx,
480
- className: "flex justify-between items-center p-2 bg-gray-50 dark:bg-gray-700 rounded"
481
- },
482
- /* @__PURE__ */ React.createElement("span", { className: "text-sm text-gray-600 dark:text-gray-400" }, point.label || point.timestamp),
483
- /* @__PURE__ */ React.createElement("span", { className: "text-sm font-semibold text-gray-900 dark:text-white" }, typeof point.value === "number" ? point.value.toFixed(2) : point.value)
505
+ dataKey: "label",
506
+ tick: { fontSize: 11, fill: "#64748b" },
507
+ tickLine: false,
508
+ axisLine: { stroke: "#cbd5e1" }
509
+ }
510
+ ), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: "#64748b" }, tickLine: false, axisLine: false }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(
511
+ import_recharts2.Line,
512
+ {
513
+ type: "monotone",
514
+ dataKey: "value",
515
+ name: "Value",
516
+ stroke: lineColor,
517
+ strokeWidth: 2.5,
518
+ dot: { r: 3.5, strokeWidth: 2, fill: lineColor },
519
+ activeDot: { r: 5 }
520
+ }
484
521
  ))));
485
522
  }
486
- function renderTable(data) {
487
- if (!data.columns || !data.rows) {
488
- return /* @__PURE__ */ React.createElement("div", { className: "text-red-500" }, "Invalid table data");
523
+ function RadarChartView({ data }) {
524
+ if (!Array.isArray(data) || data.length === 0) {
525
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid radar chart data");
489
526
  }
490
- return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 rounded-lg shadow overflow-x-auto" }, /* @__PURE__ */ React.createElement("table", { className: "w-full text-sm" }, /* @__PURE__ */ React.createElement("thead", { className: "bg-gray-100 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600" }, /* @__PURE__ */ React.createElement("tr", null, data.columns.map((col, idx) => /* @__PURE__ */ React.createElement(
527
+ const productNames = Array.from(
528
+ new Set(data.flatMap((item) => Object.keys(item).filter((key) => key !== "attribute")))
529
+ );
530
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: 300 }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.RadarChart, { cx: "50%", cy: "50%", outerRadius: "80%", data }, /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarGrid, { stroke: "#e2e8f0" }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarAngleAxis, { dataKey: "attribute", tick: { fontSize: 11, fill: "#64748b" } }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.PolarRadiusAxis, { tick: { fontSize: 10, fill: "#64748b" } }), productNames.map((productName, index) => /* @__PURE__ */ import_react5.default.createElement(
531
+ import_recharts2.Radar,
532
+ {
533
+ key: productName,
534
+ name: productName,
535
+ dataKey: productName,
536
+ stroke: getColor(index),
537
+ fill: getColor(index),
538
+ fillOpacity: 0.4
539
+ }
540
+ )), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Tooltip, { content: /* @__PURE__ */ import_react5.default.createElement(CustomTooltip, null) }), /* @__PURE__ */ import_react5.default.createElement(import_recharts2.Legend, { wrapperStyle: { fontSize: 12 } }))));
541
+ }
542
+ function TableView({ data }) {
543
+ if (!(data == null ? void 0 : data.columns) || !(data == null ? void 0 : data.rows)) {
544
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid table data");
545
+ }
546
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement("table", { className: "w-full text-sm border-collapse" }, /* @__PURE__ */ import_react5.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("tr", null, data.columns.map((col, idx) => /* @__PURE__ */ import_react5.default.createElement(
491
547
  "th",
492
548
  {
493
549
  key: idx,
494
- className: "px-4 py-2 text-left font-semibold text-gray-900 dark:text-white"
550
+ className: "px-4 py-3 text-left text-xs font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap uppercase tracking-wider"
495
551
  },
496
552
  col
497
- )))), /* @__PURE__ */ React.createElement("tbody", { className: "divide-y divide-gray-200 dark:divide-gray-600" }, data.rows.map((row, rowIdx) => /* @__PURE__ */ React.createElement(
553
+ )))), /* @__PURE__ */ import_react5.default.createElement("tbody", { className: "divide-y divide-slate-100 dark:divide-white/5" }, data.rows.map((row, rowIdx) => /* @__PURE__ */ import_react5.default.createElement(
498
554
  "tr",
499
555
  {
500
556
  key: rowIdx,
501
- className: "hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
557
+ className: "hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors"
502
558
  },
503
- row.map((cell, cellIdx) => /* @__PURE__ */ React.createElement(
559
+ row.map((cell, cellIdx) => /* @__PURE__ */ import_react5.default.createElement(
504
560
  "td",
505
561
  {
506
562
  key: cellIdx,
507
- className: "px-4 py-2 text-gray-700 dark:text-gray-300"
563
+ className: "px-4 py-3 text-slate-600 dark:text-white/70 text-sm"
508
564
  },
509
565
  String(cell)
510
566
  ))
511
- )))));
567
+ ))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, data.rows.length, " row", data.rows.length !== 1 ? "s" : "")));
512
568
  }
513
- function renderProductCarousel(data) {
569
+ function CarouselView({
570
+ data,
571
+ onAddToCart,
572
+ primaryColor
573
+ }) {
514
574
  if (!Array.isArray(data)) {
515
- return /* @__PURE__ */ React.createElement("div", { className: "text-red-500" }, "Invalid carousel data");
575
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "text-xs text-red-500" }, "Invalid carousel data");
516
576
  }
517
- return /* @__PURE__ */ React.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React.createElement("div", { className: "flex gap-4 pb-4" }, data.map((product) => /* @__PURE__ */ React.createElement(
518
- "div",
577
+ const products = data.map((product) => ({
578
+ id: product.id,
579
+ name: product.name,
580
+ brand: product.brand,
581
+ price: product.price,
582
+ image: product.image,
583
+ link: typeof product.link === "string" ? product.link : void 0,
584
+ description: product.description,
585
+ inStock: product.inStock
586
+ }));
587
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react5.default.createElement(
588
+ ProductCarousel,
519
589
  {
520
- key: product.id,
521
- className: "flex-shrink-0 w-64 bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow"
522
- },
523
- product.image && /* @__PURE__ */ React.createElement("div", { className: "relative w-full h-40 bg-gray-200" }, /* @__PURE__ */ React.createElement(
524
- import_image2.default,
525
- {
526
- src: product.image,
527
- alt: product.name,
528
- fill: true,
529
- className: "object-cover",
530
- sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
531
- }
532
- )),
533
- /* @__PURE__ */ React.createElement("div", { className: "p-4 space-y-2" }, /* @__PURE__ */ React.createElement("h4", { className: "font-semibold text-gray-900 dark:text-white line-clamp-2" }, product.name), product.brand && /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-500 dark:text-gray-400" }, "Brand: ", product.brand), product.price && /* @__PURE__ */ React.createElement("p", { className: "text-lg font-bold text-gray-900 dark:text-white" }, "$", typeof product.price === "number" ? product.price.toFixed(2) : product.price), product.description && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400 line-clamp-2" }, product.description), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2 pt-2" }, /* @__PURE__ */ React.createElement(
534
- "span",
535
- {
536
- className: `text-xs px-2 py-1 rounded flex-1 text-center ${product.inStock ? "bg-green-100 text-green-800" : "bg-red-100 text-red-800"}`
537
- },
538
- product.inStock ? "In Stock" : "Out of Stock"
539
- )))
540
- ))));
541
- }
542
- function renderText(data) {
543
- const content = (data == null ? void 0 : data.content) || String(data);
544
- return /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 p-4 rounded-lg shadow prose dark:prose-invert max-w-none" }, /* @__PURE__ */ React.createElement("p", { className: "text-gray-700 dark:text-gray-300 whitespace-pre-wrap" }, content));
590
+ products,
591
+ primaryColor: primaryColor != null ? primaryColor : "#6366f1",
592
+ onAddToCart: (p) => onAddToCart == null ? void 0 : onAddToCart(p)
593
+ }
594
+ ));
545
595
  }
546
- function generateColor(index) {
547
- const colors = [
548
- "#3B82F6",
549
- // blue
550
- "#10B981",
551
- // green
552
- "#F59E0B",
553
- // amber
554
- "#EF4444",
555
- // red
556
- "#8B5CF6",
557
- // purple
558
- "#EC4899",
559
- // pink
560
- "#06B6D4",
561
- // cyan
562
- "#F97316"
563
- // orange
564
- ];
565
- return colors[index % colors.length];
596
+ function TextView({ data }) {
597
+ const content = (data == null ? void 0 : data.content) || String(data != null ? data : "");
598
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 p-4 shadow-sm" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed" }, content));
566
599
  }
567
600
 
568
601
  // src/components/MessageBubble.tsx
@@ -646,41 +679,51 @@ function stripStructuredUiLabels(raw) {
646
679
  );
647
680
  }
648
681
  function extractBareJsonObject(raw) {
649
- const start = raw.indexOf("{");
682
+ let start = raw.indexOf("{");
650
683
  if (start === -1) return null;
651
- let depth = 0;
652
- let inString = false;
653
- let escape = false;
654
- for (let i = start; i < raw.length; i += 1) {
655
- const ch = raw[i];
656
- if (escape) {
657
- escape = false;
658
- continue;
659
- }
660
- if (ch === "\\" && inString) {
661
- escape = true;
662
- continue;
663
- }
664
- if (ch === '"') {
665
- inString = !inString;
666
- continue;
667
- }
668
- if (inString) continue;
669
- if (ch === "{") depth += 1;
670
- if (ch === "}") {
671
- depth -= 1;
672
- if (depth === 0) {
673
- return raw.slice(start, i + 1);
684
+ let bestJson = null;
685
+ let maxLen = 0;
686
+ while (start !== -1) {
687
+ let depth = 0;
688
+ let inString = false;
689
+ let escape = false;
690
+ for (let i = start; i < raw.length; i += 1) {
691
+ const ch = raw[i];
692
+ if (escape) {
693
+ escape = false;
694
+ continue;
695
+ }
696
+ if (ch === "\\" && inString) {
697
+ escape = true;
698
+ continue;
699
+ }
700
+ if (ch === '"') {
701
+ inString = !inString;
702
+ continue;
703
+ }
704
+ if (inString) continue;
705
+ if (ch === "{") depth += 1;
706
+ else if (ch === "}") {
707
+ depth -= 1;
708
+ if (depth === 0) {
709
+ const candidate = raw.slice(start, i + 1);
710
+ if (candidate.length > maxLen) {
711
+ maxLen = candidate.length;
712
+ bestJson = candidate;
713
+ }
714
+ break;
715
+ }
674
716
  }
675
717
  }
718
+ start = raw.indexOf("{", start + 1);
676
719
  }
677
- return null;
720
+ return bestJson;
678
721
  }
679
722
  function extractStructuredPayload(raw) {
680
723
  var _a, _b;
681
724
  let working = raw;
682
725
  const fenceRegex = /```(?:[a-z]+)?\s*([\s\S]*?)```/gi;
683
- for (const match of raw.matchAll(fenceRegex)) {
726
+ for (const match of Array.from(raw.matchAll(fenceRegex))) {
684
727
  const body = (_b = (_a = match[1]) == null ? void 0 : _a.trim()) != null ? _b : "";
685
728
  if (!looksLikeStructuredPayload(body)) continue;
686
729
  working = working.replace(match[0], "");
@@ -704,21 +747,30 @@ function extractStructuredPayload(raw) {
704
747
  }
705
748
  function isLikelyUiOnlyMessage(text) {
706
749
  const trimmed = text.trim();
707
- return trimmed.length === 0 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary)\s*:?\s*$/i.test(trimmed);
750
+ return trimmed.length === 0 || trimmed.length < 30 || /^(chart data|table data|visualization|visual representation|product catalog|product recommendations|catalog summary|availability|inventory status|details)\s*:?\s*$/i.test(trimmed);
708
751
  }
709
752
  function resolveImage(data) {
710
753
  const isPlaceholder = (val) => typeof val === "string" && (val === "..." || val === "" || val.toLowerCase() === "null" || val.toLowerCase() === "undefined");
711
- for (const key of ["image", "img", "thumbnail"]) {
754
+ for (const key of ["image", "img", "thumbnail", "images", "product_image", "Image", "Thumbnail"]) {
712
755
  const v = data[key];
713
756
  if (typeof v === "string" && v && !isPlaceholder(v)) return v;
714
- }
715
- if (Array.isArray(data.images) && typeof data.images[0] === "string" && !isPlaceholder(data.images[0])) {
716
- return data.images[0];
757
+ if (Array.isArray(v) && typeof v[0] === "string" && v[0] && !isPlaceholder(v[0])) return v[0];
717
758
  }
718
759
  return void 0;
719
760
  }
761
+ function getMetadataValue(meta, keys) {
762
+ const searchKeys = keys.map((k) => k.toLowerCase());
763
+ const metaKeys = Object.keys(meta);
764
+ const foundKey = metaKeys.find((k) => searchKeys.includes(k.toLowerCase()));
765
+ if (foundKey) return meta[foundKey];
766
+ const partialKey = metaKeys.find((k) => {
767
+ const kLow = k.toLowerCase();
768
+ return searchKeys.some((sk) => kLow.includes(sk) || sk.includes(kLow));
769
+ });
770
+ return partialKey ? meta[partialKey] : void 0;
771
+ }
720
772
  function normaliseChild(children) {
721
- if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react5.default.isValidElement(children)) {
773
+ if (typeof children === "object" && children !== null && !Array.isArray(children) && !import_react6.default.isValidElement(children)) {
722
774
  return JSON.stringify(children);
723
775
  }
724
776
  return children;
@@ -732,7 +784,7 @@ function formatColumnLabel(value) {
732
784
  function DataTable({ config, viewportSize = "large" }) {
733
785
  const isCompact = viewportSize === "compact";
734
786
  const isMedium = viewportSize === "medium";
735
- const columns = import_react5.default.useMemo(() => {
787
+ const columns = import_react6.default.useMemo(() => {
736
788
  const rowKeys = Array.from(
737
789
  new Set(
738
790
  config.data.flatMap((row) => Object.keys(row))
@@ -762,27 +814,27 @@ function DataTable({ config, viewportSize = "large" }) {
762
814
  return rowKeys.map((key) => ({ label: formatColumnLabel(key), accessor: key }));
763
815
  }, [config]);
764
816
  if (!config.data.length || !columns.length) {
765
- return /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-400 italic my-2" }, "No data to display.");
817
+ return /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-400 italic my-2" }, "No data to display.");
766
818
  }
767
819
  const formatCell = (val) => {
768
820
  if (val === null || val === void 0) return "\u2014";
769
821
  if (typeof val === "boolean") return val ? "\u2713" : "\u2717";
770
822
  return String(val);
771
823
  };
772
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react5.default.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement("table", { className: `w-full text-left border-collapse ${isCompact ? "min-w-[240px] text-xs" : isMedium ? "min-w-[280px] text-[13px]" : "min-w-[320px] text-sm"}` }, /* @__PURE__ */ import_react5.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react5.default.createElement("tr", null, columns.map((column) => /* @__PURE__ */ import_react5.default.createElement(
824
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden" }, config.title && /* @__PURE__ */ import_react6.default.createElement("div", { className: "px-4 py-2.5 bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs font-semibold text-slate-600 dark:text-white/70 uppercase tracking-wide" }, config.title)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react6.default.createElement("table", { className: `w-full text-left border-collapse ${isCompact ? "min-w-[240px] text-xs" : isMedium ? "min-w-[280px] text-[13px]" : "min-w-[320px] text-sm"}` }, /* @__PURE__ */ import_react6.default.createElement("thead", { className: "bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10" }, /* @__PURE__ */ import_react6.default.createElement("tr", null, columns.map((column) => /* @__PURE__ */ import_react6.default.createElement(
773
825
  "th",
774
826
  {
775
827
  key: column.label,
776
828
  className: `${isCompact ? "px-2.5 py-2" : "px-4 py-3"} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`
777
829
  },
778
830
  column.label
779
- )))), /* @__PURE__ */ import_react5.default.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ import_react5.default.createElement(
831
+ )))), /* @__PURE__ */ import_react6.default.createElement("tbody", null, config.data.map((row, ri) => /* @__PURE__ */ import_react6.default.createElement(
780
832
  "tr",
781
833
  {
782
834
  key: ri,
783
835
  className: "border-b border-slate-100 dark:border-white/5 last:border-0 hover:bg-slate-50/60 dark:hover:bg-white/5 transition-colors"
784
836
  },
785
- columns.map((column) => /* @__PURE__ */ import_react5.default.createElement(
837
+ columns.map((column) => /* @__PURE__ */ import_react6.default.createElement(
786
838
  "td",
787
839
  {
788
840
  key: column.label,
@@ -790,10 +842,17 @@ function DataTable({ config, viewportSize = "large" }) {
790
842
  },
791
843
  formatCell(row[column.accessor])
792
844
  ))
793
- ))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
845
+ ))))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "px-4 py-2 bg-slate-50 dark:bg-white/5 border-t border-slate-100 dark:border-white/5" }, /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-[11px] text-slate-400 dark:text-white/30" }, config.data.length, " row", config.data.length !== 1 ? "s" : "")));
794
846
  }
795
847
  function normalizeTabularRows(rows, columns) {
796
848
  if (!Array.isArray(rows)) return [];
849
+ const SYNONYMS = {
850
+ name: ["product", "item", "title", "label", "heading", "product name", "item name"],
851
+ price: ["cost", "amount", "msrp", "price", "rate", "value", "price_usd"],
852
+ brand: ["manufacturer", "vendor", "make", "company", "brand_name", "supplier"],
853
+ image: ["imageUrl", "thumbnail", "img", "url", "photo", "picture", "media"],
854
+ stock: ["inventory", "quantity", "count", "availability", "stock_level", "in stock", "status"]
855
+ };
797
856
  return rows.map((row) => {
798
857
  if (Array.isArray(row)) {
799
858
  const keys = Array.isArray(columns) && columns.length > 0 ? columns : row.map((_, index) => `column_${index + 1}`);
@@ -803,7 +862,36 @@ function normalizeTabularRows(rows, columns) {
803
862
  }, {});
804
863
  }
805
864
  if (row && typeof row === "object") {
806
- return row;
865
+ const result = __spreadValues({}, row);
866
+ if (Array.isArray(columns)) {
867
+ columns.forEach((col) => {
868
+ if (result[col] !== void 0) return;
869
+ const rowKeys = Object.keys(row);
870
+ const colLower = col.toLowerCase().replace(/_/g, " ");
871
+ const foundKey = rowKeys.find((rk) => {
872
+ const rkLower = rk.toLowerCase().replace(/_/g, " ");
873
+ return rkLower === colLower || rkLower.includes(colLower) || colLower.includes(rkLower);
874
+ });
875
+ if (foundKey) {
876
+ result[col] = row[foundKey];
877
+ return;
878
+ }
879
+ for (const [target, aliases] of Object.entries(SYNONYMS)) {
880
+ const isMatch = target === colLower || aliases.some((a) => colLower.includes(a) || a.includes(colLower));
881
+ if (isMatch) {
882
+ const mappedKey = rowKeys.find((rk) => {
883
+ const rkL = rk.toLowerCase();
884
+ return rkL === target || aliases.some((a) => rkL.includes(a) || a.includes(rkL));
885
+ });
886
+ if (mappedKey) {
887
+ result[col] = row[mappedKey];
888
+ break;
889
+ }
890
+ }
891
+ }
892
+ });
893
+ }
894
+ return result;
807
895
  }
808
896
  return { value: row };
809
897
  }).filter((row) => Object.keys(row).length > 0);
@@ -823,7 +911,7 @@ function resolveStructuredRows(config) {
823
911
  }
824
912
  function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = "large" }) {
825
913
  var _a;
826
- const result = import_react5.default.useMemo(() => {
914
+ const result = import_react6.default.useMemo(() => {
827
915
  if (isStreaming) return { loading: true };
828
916
  try {
829
917
  const clean = rawContent.replace(/^```[a-z]*\s*/i, "").replace(/```\s*$/, "").trim();
@@ -846,12 +934,15 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
846
934
  config2.view = "chart";
847
935
  config2.chartType = config2.chartType || "bar";
848
936
  }
849
- if (!config2.view) {
850
- if (config2.type === "products" || Array.isArray(config2.items) || hasProductLikeData) {
937
+ if (!config2.view || ["pie", "bar", "line", "pie_chart", "bar_chart", "line_chart"].includes(String(config2.view))) {
938
+ const viewStr = String(config2.view || "").toLowerCase();
939
+ if (viewStr.includes("carousel") || config2.type === "products" || Array.isArray(config2.items) || hasProductLikeData) {
851
940
  config2.view = "carousel";
852
- } else if (hasAggregationLikeData || typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
941
+ } else if (viewStr.includes("chart") || viewStr.includes("pie") || viewStr.includes("bar") || viewStr.includes("line") || hasAggregationLikeData || typeof config2.type === "string" && ["pie", "bar", "line"].includes(config2.type) || typeof config2.chartType === "string" && ["pie", "bar", "line"].includes(config2.chartType)) {
853
942
  config2.view = "chart";
854
- config2.chartType = config2.chartType || config2.type || "bar";
943
+ config2.chartType = config2.chartType || viewStr.replace("_chart", "") || config2.type || "bar";
944
+ } else if (viewStr.includes("table")) {
945
+ config2.view = "table";
855
946
  } else {
856
947
  config2.view = "table";
857
948
  }
@@ -865,10 +956,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
865
956
  }
866
957
  }, [rawContent, isStreaming]);
867
958
  if ("loading" in result) {
868
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
959
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4 p-8 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex flex-col items-center justify-center gap-3 animate-pulse" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-5 h-5 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic" }, "Preparing view..."));
869
960
  }
870
961
  if ("error" in result) {
871
- return /* @__PURE__ */ import_react5.default.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ import_react5.default.createElement("code", null, rawContent));
962
+ return /* @__PURE__ */ import_react6.default.createElement("pre", { className: "p-4 my-2 bg-slate-900 text-slate-100 rounded-lg text-[10px] overflow-auto max-h-40" }, /* @__PURE__ */ import_react6.default.createElement("code", null, rawContent));
872
963
  }
873
964
  const { config } = result;
874
965
  const isCompact = viewportSize === "compact";
@@ -876,7 +967,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
876
967
  const hasDescription = typeof config.description === "string" && config.description.trim().length > 0;
877
968
  switch (config.view) {
878
969
  case "chart":
879
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(
970
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: `${isCompact ? "my-4 p-3" : "my-6 p-4"} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden` }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "text-[11px] mb-3" : "text-xs mb-4"} font-semibold text-slate-500 px-2` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `px-2 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(
880
971
  DynamicChart,
881
972
  {
882
973
  config: {
@@ -890,23 +981,23 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
890
981
  accentColor,
891
982
  viewportSize
892
983
  }
893
- ), hasInsights && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight) => /* @__PURE__ */ import_react5.default.createElement(
984
+ ), hasInsights && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-4 flex flex-wrap gap-2 px-2" }, (_a = config.insights) == null ? void 0 : _a.map((insight, i) => /* @__PURE__ */ import_react6.default.createElement(
894
985
  "span",
895
986
  {
896
- key: insight,
987
+ key: `insight-${i}`,
897
988
  className: `rounded-full border border-emerald-200 bg-emerald-50 ${isCompact ? "px-2.5 py-1 text-[10px]" : "px-3 py-1 text-[11px]"} font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300`
898
989
  },
899
- insight
990
+ String(insight)
900
991
  ))));
901
992
  case "carousel":
902
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(ProductCarousel, { products: config.data.map((item) => {
993
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-4" }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "mb-1.5 text-[11px]" : "mb-2 text-xs"} font-semibold text-slate-500` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(ProductCarousel, { products: config.data.map((item) => {
903
994
  var _a2;
904
995
  return __spreadProps(__spreadValues({}, item), {
905
996
  image: (_a2 = item.image) != null ? _a2 : typeof resolveImage === "function" ? resolveImage(item) : void 0
906
997
  });
907
998
  }), primaryColor, onAddToCart }));
908
999
  case "table":
909
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ import_react5.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react5.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react5.default.createElement(DataTable, { config: {
1000
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: `${isCompact ? "my-3 p-3 max-h-[320px]" : "my-4 p-4 max-h-[400px]"} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto` }, config.title && /* @__PURE__ */ import_react6.default.createElement("h4", { className: `${isCompact ? "text-[11px]" : "text-xs"} font-semibold text-slate-500 mb-2` }, config.title), hasDescription && /* @__PURE__ */ import_react6.default.createElement("p", { className: `mb-3 ${isCompact ? "text-xs" : "text-sm"} text-slate-500 dark:text-white/60` }, config.description), /* @__PURE__ */ import_react6.default.createElement(DataTable, { config: {
910
1001
  type: "table",
911
1002
  title: config.title,
912
1003
  description: config.description,
@@ -931,44 +1022,59 @@ function MessageBubble({
931
1022
  const isUser = message.role === "user";
932
1023
  const isCompact = viewportSize === "compact";
933
1024
  const isMedium = viewportSize === "medium";
934
- const [showSources, setShowSources] = import_react5.default.useState(false);
935
- const hasStructuredProductBlock = import_react5.default.useMemo(
936
- () => /```(?:ui|json|chart)\s*[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products|table)"?/i.test(message.content) || /\{[\s\S]*?"?(?:view|type|data|products)"?\s*:\s*"?(?:carousel|products)"?[\s\S]*\}/i.test(message.content) && looksLikeStructuredPayload(message.content),
937
- [message.content]
938
- );
939
- const structuredContent = import_react5.default.useMemo(
1025
+ const [showSources, setShowSources] = import_react6.default.useState(false);
1026
+ const structuredContent = import_react6.default.useMemo(
940
1027
  () => isUser ? { payload: null, text: message.content } : extractStructuredPayload(message.content),
941
1028
  [isUser, message.content]
942
1029
  );
943
- const shouldRenderStructuredOnly = !isUser && Boolean(structuredContent.payload) && isLikelyUiOnlyMessage(structuredContent.text);
944
- const productsFromSources = import_react5.default.useMemo(() => {
1030
+ const hasRichUI = import_react6.default.useMemo(() => {
1031
+ if (message.uiTransformation) {
1032
+ const type = message.uiTransformation.type;
1033
+ if (type && !["text", "table"].includes(type)) return true;
1034
+ }
1035
+ if (structuredContent.payload) {
1036
+ return /"?(?:view|type|chartType)"?\s*:\s*"?(?:chart|carousel|pie|bar|line|product_carousel)"?/i.test(structuredContent.payload);
1037
+ }
1038
+ return false;
1039
+ }, [message.uiTransformation, structuredContent.payload]);
1040
+ const shouldRenderStructuredOnly = !isUser && hasRichUI && isLikelyUiOnlyMessage(structuredContent.text);
1041
+ const productsFromSources = import_react6.default.useMemo(() => {
945
1042
  if (isUser || !sources) return [];
946
1043
  return sources.filter((s) => {
947
1044
  var _a;
948
1045
  const m = (_a = s.metadata) != null ? _a : {};
949
- return m.price || m.image || m.img || m.thumbnail || m.images || m.brand || m.type === "product";
1046
+ const keys = Object.keys(m).map((k) => k.toLowerCase());
1047
+ const hasProductKey = keys.some(
1048
+ (k) => ["price", "image", "img", "thumbnail", "images", "brand", "product", "sku", "category", "model", "cost"].includes(k)
1049
+ );
1050
+ const hasPricePattern = /\$\s*\d+/.test(s.content);
1051
+ return hasProductKey || hasPricePattern || m.type === "product";
950
1052
  }).map((s) => {
951
- var _a, _b, _c, _d;
1053
+ var _a, _b;
952
1054
  const m = (_a = s.metadata) != null ? _a : {};
1055
+ const name = getMetadataValue(m, ["name", "product", "title", "label", "item"]);
1056
+ const brand = getMetadataValue(m, ["brand", "manufacturer", "vendor", "make"]);
1057
+ const price = getMetadataValue(m, ["price", "cost", "amount", "msrp", "rate"]);
953
1058
  return {
954
1059
  id: s.id,
955
- name: (_d = (_c = (_b = m.name) != null ? _b : m.title) != null ? _c : s.content.split("\n")[0]) != null ? _d : "Unknown Product",
956
- brand: m.brand,
957
- price: m.price,
1060
+ name: (_b = name != null ? name : s.content.split("\n")[0]) != null ? _b : "Unknown Product",
1061
+ brand,
1062
+ price,
958
1063
  image: resolveImage(m),
959
- link: m.link,
1064
+ link: getMetadataValue(m, ["link", "url", "product_url"]),
960
1065
  description: s.content
961
1066
  };
962
1067
  });
963
1068
  }, [sources, isUser]);
964
- const { productsFromContent, cleanContent } = import_react5.default.useMemo(() => {
1069
+ const { productsFromContent, cleanContent } = import_react6.default.useMemo(() => {
1070
+ var _a, _b;
965
1071
  if (isUser) {
966
1072
  return { productsFromContent: [], cleanContent: message.content };
967
1073
  }
968
1074
  const jsonRegex = /```(?:json|ui)?\s*([\s\S]*?)\s*```/g;
969
1075
  const products = [];
970
1076
  let content = structuredContent.text;
971
- const payloadCandidates = [structuredContent.payload, ...content.matchAll(jsonRegex).map((match) => match[1])].filter(Boolean);
1077
+ const payloadCandidates = [structuredContent.payload, ...Array.from(content.matchAll(jsonRegex)).map((match) => match[1])].filter(Boolean);
972
1078
  for (const candidate of payloadCandidates) {
973
1079
  try {
974
1080
  const data = JSON.parse(sanitizeJson(candidate));
@@ -976,9 +1082,9 @@ function MessageBubble({
976
1082
  if ((data.type === "products" || data.view === "carousel" || data.view === "table" || Array.isArray(data.products)) && itemSet) {
977
1083
  products.push(
978
1084
  ...itemSet.map((item) => {
979
- var _a;
1085
+ var _a2;
980
1086
  return __spreadProps(__spreadValues({}, item), {
981
- image: (_a = item.image) != null ? _a : resolveImage(item)
1087
+ image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
982
1088
  });
983
1089
  })
984
1090
  );
@@ -987,15 +1093,15 @@ function MessageBubble({
987
1093
  }
988
1094
  }
989
1095
  if (content.includes('"type": "products"') || content.includes('"type":"products"')) {
990
- for (const match of content.matchAll(jsonRegex)) {
1096
+ for (const match of Array.from(content.matchAll(jsonRegex))) {
991
1097
  try {
992
1098
  const data = JSON.parse(sanitizeJson(match[1]));
993
1099
  if (data.type === "products" && Array.isArray(data.items)) {
994
1100
  products.push(
995
1101
  ...data.items.map((item) => {
996
- var _a;
1102
+ var _a2;
997
1103
  return __spreadProps(__spreadValues({}, item), {
998
- image: (_a = item.image) != null ? _a : resolveImage(item)
1104
+ image: (_a2 = item.image) != null ? _a2 : resolveImage(item)
999
1105
  });
1000
1106
  })
1001
1107
  );
@@ -1005,9 +1111,42 @@ function MessageBubble({
1005
1111
  }
1006
1112
  }
1007
1113
  }
1114
+ const bulletRegex = /(?:[•*-]\s*)?([^•\n\-\$*–—\(]+?)(?:\s*\(?Price\s*[:\-–—]?\s*)?(?:\s*[:\-–—]\s*|\s+)\$?([\d,.]+)(?:\s*USD)?/gi;
1115
+ const matches = Array.from(content.matchAll(bulletRegex));
1116
+ if (matches.length >= 2) {
1117
+ const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
1118
+ for (const match of matches) {
1119
+ let name = ((_a = match[1]) == null ? void 0 : _a.trim()) || "";
1120
+ name = name.replace(/\s*\(?Price\s*$/i, "").replace(/[:\-–—]\s*$/g, "").trim();
1121
+ let price = ((_b = match[2]) == null ? void 0 : _b.trim()) || "";
1122
+ price = price.replace(/[,\s]+$/, "").trim();
1123
+ if (name && price) {
1124
+ const newProduct = {
1125
+ id: `text-prod-${name}-${price}`,
1126
+ name,
1127
+ price: `$${price}`
1128
+ };
1129
+ const normName = normalize(name);
1130
+ const sourceMatch = productsFromSources.find((s) => {
1131
+ const sn = normalize(s.name);
1132
+ return sn.includes(normName) || normName.includes(sn);
1133
+ });
1134
+ if (sourceMatch) {
1135
+ newProduct.image = sourceMatch.image;
1136
+ newProduct.brand = sourceMatch.brand;
1137
+ newProduct.link = sourceMatch.link;
1138
+ newProduct.description = sourceMatch.description;
1139
+ }
1140
+ products.push(newProduct);
1141
+ content = content.replace(match[0], `
1142
+ **${name}** \u2014 $${price}`);
1143
+ }
1144
+ }
1145
+ content = content.replace(/\n{3,}/g, "\n\n").trim();
1146
+ }
1008
1147
  return { productsFromContent: products, cleanContent: content.trim() };
1009
- }, [message.content, isUser, structuredContent]);
1010
- const allProducts = import_react5.default.useMemo(() => {
1148
+ }, [message.content, isUser, structuredContent, productsFromSources]);
1149
+ const allProducts = import_react6.default.useMemo(() => {
1011
1150
  if (productsFromContent.length > 0) return productsFromContent;
1012
1151
  const seen = /* @__PURE__ */ new Set();
1013
1152
  const contentLower = message.content.toLowerCase();
@@ -1023,7 +1162,7 @@ function MessageBubble({
1023
1162
  return false;
1024
1163
  });
1025
1164
  }, [productsFromSources, productsFromContent, message.content]);
1026
- const processedMarkdown = import_react5.default.useMemo(() => {
1165
+ const processedMarkdown = import_react6.default.useMemo(() => {
1027
1166
  let raw = structuredContent.payload ? structuredContent.text : cleanContent || message.content;
1028
1167
  const hasStructuredUiBlock = Boolean(structuredContent.payload) || /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|chartType|type|data|items|rows|products|results)"\s*:/i.test(raw);
1029
1168
  raw = raw.replace(/([^\n])\n\|/g, "$1\n\n|").replace(/(\|[^\n]*\|)\n\n+(?=\|)/g, "$1\n");
@@ -1057,16 +1196,16 @@ ${match.trim()}
1057
1196
  }
1058
1197
  return raw;
1059
1198
  }, [cleanContent, message.content, isStreaming, structuredContent]);
1060
- const markdownComponents = import_react5.default.useMemo(
1199
+ const markdownComponents = import_react6.default.useMemo(
1061
1200
  () => ({
1062
1201
  // Wrap in not-prose so Tailwind Typography resets don't clobber our styles.
1063
1202
  // prose applies display:block and padding:0 to table/th/td — not-prose opts out.
1064
1203
  table: (_a) => {
1065
1204
  var props = __objRest(_a, []);
1066
1205
  if (isStreaming) {
1067
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
1206
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
1068
1207
  }
1069
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "not-prose overflow-hidden my-5 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm bg-white dark:bg-slate-900/50" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react5.default.createElement(
1208
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "not-prose overflow-hidden my-5 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm bg-white dark:bg-slate-900/50" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ import_react6.default.createElement(
1070
1209
  "table",
1071
1210
  __spreadValues({
1072
1211
  className: "!table w-full text-left border-collapse min-w-[400px] text-sm"
@@ -1075,7 +1214,7 @@ ${match.trim()}
1075
1214
  },
1076
1215
  thead: (_b) => {
1077
1216
  var props = __objRest(_b, []);
1078
- return /* @__PURE__ */ import_react5.default.createElement(
1217
+ return /* @__PURE__ */ import_react6.default.createElement(
1079
1218
  "thead",
1080
1219
  __spreadValues({
1081
1220
  className: "!table-header-group bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10"
@@ -1084,11 +1223,11 @@ ${match.trim()}
1084
1223
  },
1085
1224
  tbody: (_c) => {
1086
1225
  var props = __objRest(_c, []);
1087
- return /* @__PURE__ */ import_react5.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
1226
+ return /* @__PURE__ */ import_react6.default.createElement("tbody", __spreadValues({ className: "!table-row-group divide-y divide-slate-100 dark:divide-white/5" }, props));
1088
1227
  },
1089
1228
  tr: (_d) => {
1090
1229
  var props = __objRest(_d, []);
1091
- return /* @__PURE__ */ import_react5.default.createElement(
1230
+ return /* @__PURE__ */ import_react6.default.createElement(
1092
1231
  "tr",
1093
1232
  __spreadValues({
1094
1233
  className: "!table-row hover:bg-slate-50/70 dark:hover:bg-white/5 transition-colors"
@@ -1097,7 +1236,7 @@ ${match.trim()}
1097
1236
  },
1098
1237
  th: (_e) => {
1099
1238
  var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
1100
- return /* @__PURE__ */ import_react5.default.createElement(
1239
+ return /* @__PURE__ */ import_react6.default.createElement(
1101
1240
  "th",
1102
1241
  __spreadValues({
1103
1242
  className: "!table-cell px-4 py-3 font-bold text-slate-700 dark:text-white/90 whitespace-nowrap text-[11px] uppercase tracking-wider text-left"
@@ -1107,7 +1246,7 @@ ${match.trim()}
1107
1246
  },
1108
1247
  td: (_g) => {
1109
1248
  var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
1110
- return /* @__PURE__ */ import_react5.default.createElement(
1249
+ return /* @__PURE__ */ import_react6.default.createElement(
1111
1250
  "td",
1112
1251
  __spreadValues({
1113
1252
  className: "!table-cell px-4 py-3 text-slate-600 dark:text-white/70 whitespace-nowrap text-sm"
@@ -1128,7 +1267,7 @@ ${match.trim()}
1128
1267
  var _a;
1129
1268
  const lang = (_a = /language-(\w+)/.exec(className != null ? className : "")) == null ? void 0 : _a[1];
1130
1269
  if (!inline && (lang === "ui" || lang === "chart")) {
1131
- return /* @__PURE__ */ import_react5.default.createElement(
1270
+ return /* @__PURE__ */ import_react6.default.createElement(
1132
1271
  UIDispatcher,
1133
1272
  {
1134
1273
  rawContent: String(children != null ? children : "").trim(),
@@ -1143,7 +1282,7 @@ ${match.trim()}
1143
1282
  if (!inline && lang === "json") {
1144
1283
  const content = String(children != null ? children : "").trim();
1145
1284
  if (looksLikeStructuredPayload(content)) {
1146
- return /* @__PURE__ */ import_react5.default.createElement(
1285
+ return /* @__PURE__ */ import_react6.default.createElement(
1147
1286
  UIDispatcher,
1148
1287
  {
1149
1288
  rawContent: content,
@@ -1159,7 +1298,7 @@ ${match.trim()}
1159
1298
  if (!inline) {
1160
1299
  const content = String(children != null ? children : "").trim();
1161
1300
  if (looksLikeStructuredPayload(content)) {
1162
- return /* @__PURE__ */ import_react5.default.createElement(
1301
+ return /* @__PURE__ */ import_react6.default.createElement(
1163
1302
  UIDispatcher,
1164
1303
  {
1165
1304
  rawContent: content,
@@ -1173,27 +1312,27 @@ ${match.trim()}
1173
1312
  }
1174
1313
  }
1175
1314
  if (!inline && lang === "table-loading") {
1176
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react5.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
1315
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "my-5 p-6 bg-slate-50 dark:bg-white/5 rounded-xl border border-dashed border-slate-300 dark:border-white/10 flex items-center justify-center gap-3 select-none" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-4 h-4 border-2 border-indigo-500 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ import_react6.default.createElement("p", { className: "text-xs text-slate-500 font-medium italic animate-pulse" }, "Generating data table..."));
1177
1316
  }
1178
- return /* @__PURE__ */ import_react5.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
1317
+ return /* @__PURE__ */ import_react6.default.createElement("code", __spreadValues({ className }, props), typeof children === "string" || typeof children === "number" ? children : JSON.stringify(children));
1179
1318
  }
1180
1319
  }),
1181
1320
  [primaryColor, accentColor, isStreaming, onAddToCart, viewportSize]
1182
1321
  );
1183
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react5.default.createElement(
1322
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex ${isCompact ? "gap-2" : "gap-3"} ${isUser ? "flex-row-reverse" : "flex-row"} items-start` }, /* @__PURE__ */ import_react6.default.createElement(
1184
1323
  "div",
1185
1324
  {
1186
1325
  className: `flex-shrink-0 ${isCompact ? "w-7 h-7" : "w-8 h-8"} rounded-full flex items-center justify-center shadow-lg ${isUser ? "text-white" : "bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80"}`,
1187
1326
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
1188
1327
  },
1189
- isUser ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
1190
- ), /* @__PURE__ */ import_react5.default.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react5.default.createElement(
1328
+ isUser ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.User, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"} text-white` }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.Bot, { className: `${isCompact ? "w-3.5 h-3.5" : "w-4 h-4"}` })
1329
+ ), /* @__PURE__ */ import_react6.default.createElement("div", { className: `flex flex-col gap-1 ${isCompact ? "max-w-[94%]" : isMedium ? "max-w-[92%]" : "max-w-[90%]"} ${isUser ? "items-end" : "items-start"}` }, /* @__PURE__ */ import_react6.default.createElement(
1191
1330
  "div",
1192
1331
  {
1193
1332
  className: `relative ${isCompact ? "px-3 py-2.5 text-[13px]" : "px-4 py-3 text-sm"} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser ? "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"}`,
1194
1333
  style: isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}
1195
1334
  },
1196
- isStreaming && !message.content ? /* @__PURE__ */ import_react5.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react5.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react5.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, !isUser && structuredContent.payload && /* @__PURE__ */ import_react5.default.createElement(
1335
+ isStreaming && !message.content ? /* @__PURE__ */ import_react6.default.createElement("span", { className: "flex items-center gap-1 py-1" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:0ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:150ms]" }), /* @__PURE__ */ import_react6.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" })) : /* @__PURE__ */ import_react6.default.createElement("div", { className: `prose ${isCompact ? "prose-xs" : "prose-sm"} max-w-none break-words ${isUser ? "prose-invert" : "dark:prose-invert"}` }, !isUser && structuredContent.payload && /* @__PURE__ */ import_react6.default.createElement(
1197
1336
  UIDispatcher,
1198
1337
  {
1199
1338
  rawContent: structuredContent.payload,
@@ -1203,30 +1342,46 @@ ${match.trim()}
1203
1342
  onAddToCart,
1204
1343
  viewportSize
1205
1344
  }
1206
- ), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react5.default.createElement(import_react_markdown.default, { remarkPlugins: [import_remark_gfm.default], components: markdownComponents }, processedMarkdown), !isUser && !structuredContent.payload && !!message.uiTransformation && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-4 border-t border-slate-100 dark:border-white/5 pt-4" }, /* @__PURE__ */ import_react5.default.createElement(VisualizationRenderer, { data: message.uiTransformation })), isStreaming && message.content && /* @__PURE__ */ import_react5.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
1207
- ), !isUser && !hasStructuredProductBlock && allProducts.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react5.default.createElement(
1345
+ ), !shouldRenderStructuredOnly && /* @__PURE__ */ import_react6.default.createElement(import_react_markdown.default, { components: markdownComponents }, processedMarkdown), isStreaming && message.content && /* @__PURE__ */ import_react6.default.createElement("span", { className: "inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" }))
1346
+ ), (() => {
1347
+ var _a, _b;
1348
+ if (isUser || structuredContent.payload || !message.uiTransformation) return null;
1349
+ const ui = message.uiTransformation;
1350
+ const textContent = (_b = (_a = ui.data) == null ? void 0 : _a.content) != null ? _b : "";
1351
+ const shouldShow = ui.type === "table" && allProducts.length === 0 || !["text", "table"].includes(ui.type) || ui.type === "text" && !hasRichUI && allProducts.length === 0 && textContent && !processedMarkdown.toLowerCase().includes(textContent.trim().toLowerCase());
1352
+ if (!shouldShow) return null;
1353
+ return /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-3" }, /* @__PURE__ */ import_react6.default.createElement(
1354
+ VisualizationRenderer,
1355
+ {
1356
+ data: ui,
1357
+ primaryColor,
1358
+ onAddToCart,
1359
+ className: "rounded-3xl border border-slate-200/60 dark:border-white/10 bg-white/90 dark:bg-slate-900/80 p-4"
1360
+ }
1361
+ ));
1362
+ })(), !isUser && !hasRichUI && allProducts.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full mt-1" }, /* @__PURE__ */ import_react6.default.createElement(
1208
1363
  ProductCarousel,
1209
1364
  {
1210
1365
  products: allProducts,
1211
1366
  primaryColor,
1212
1367
  onAddToCart
1213
1368
  }
1214
- )), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react5.default.createElement(
1369
+ )), !isUser && sources && sources.length > 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "w-full" }, /* @__PURE__ */ import_react6.default.createElement(
1215
1370
  "button",
1216
1371
  {
1217
1372
  onClick: () => setShowSources((s) => !s),
1218
1373
  className: "text-[11px] text-indigo-400 hover:text-indigo-300 transition-colors flex items-center gap-1 mt-1"
1219
1374
  },
1220
- showSources ? /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react5.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
1375
+ showSources ? /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ import_react6.default.createElement(import_lucide_react4.ChevronRight, { className: "w-3 h-3" }),
1221
1376
  sources.length,
1222
1377
  " source",
1223
1378
  sources.length !== 1 ? "s" : "",
1224
1379
  " used"
1225
- ), showSources && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react5.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
1380
+ ), showSources && /* @__PURE__ */ import_react6.default.createElement("div", { className: "mt-2 flex flex-col gap-2" }, sources.map((src, i) => /* @__PURE__ */ import_react6.default.createElement(SourceCard, { key: src.id, source: src, index: i }))))));
1226
1381
  }
1227
1382
 
1228
1383
  // src/components/ConfigProvider.tsx
1229
- var import_react6 = __toESM(require("react"));
1384
+ var import_react7 = __toESM(require("react"));
1230
1385
 
1231
1386
  // src/utils/templateUtils.ts
1232
1387
  function mergeDefined(base, override) {
@@ -1278,7 +1433,7 @@ var CHAT_SUGGESTIONS = [
1278
1433
  ];
1279
1434
 
1280
1435
  // src/components/ConfigProvider.tsx
1281
- var ConfigContext = (0, import_react6.createContext)(DEFAULT_CONFIG);
1436
+ var ConfigContext = (0, import_react7.createContext)(DEFAULT_CONFIG);
1282
1437
  function ConfigProvider({
1283
1438
  config,
1284
1439
  children
@@ -1287,14 +1442,14 @@ function ConfigProvider({
1287
1442
  projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
1288
1443
  ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
1289
1444
  };
1290
- return /* @__PURE__ */ import_react6.default.createElement(ConfigContext.Provider, { value: merged }, children);
1445
+ return /* @__PURE__ */ import_react7.default.createElement(ConfigContext.Provider, { value: merged }, children);
1291
1446
  }
1292
1447
  function useConfig() {
1293
- return (0, import_react6.useContext)(ConfigContext);
1448
+ return (0, import_react7.useContext)(ConfigContext);
1294
1449
  }
1295
1450
 
1296
1451
  // src/hooks/useRagChat.ts
1297
- var import_react7 = require("react");
1452
+ var import_react8 = require("react");
1298
1453
 
1299
1454
  // src/hooks/useStoredMessages.ts
1300
1455
  var React8 = __toESM(require("react"));
@@ -1355,14 +1510,14 @@ function useRagChat(projectId, options = {}) {
1355
1510
  } = options;
1356
1511
  const storageKey = `rag_chat_${projectId}`;
1357
1512
  const [messages, setMessages] = useStoredMessages(storageKey, persist);
1358
- const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
1359
- const [error, setError] = (0, import_react7.useState)(null);
1360
- const lastInputRef = (0, import_react7.useRef)("");
1361
- const messagesRef = (0, import_react7.useRef)(messages);
1362
- (0, import_react7.useEffect)(() => {
1513
+ const [isLoading, setIsLoading] = (0, import_react8.useState)(false);
1514
+ const [error, setError] = (0, import_react8.useState)(null);
1515
+ const lastInputRef = (0, import_react8.useRef)("");
1516
+ const messagesRef = (0, import_react8.useRef)(messages);
1517
+ (0, import_react8.useEffect)(() => {
1363
1518
  messagesRef.current = messages;
1364
1519
  }, [messages]);
1365
- const sendMessage = (0, import_react7.useCallback)(
1520
+ const sendMessage = (0, import_react8.useCallback)(
1366
1521
  async (text, opts) => {
1367
1522
  var _a, _b;
1368
1523
  const trimmed = text.trim();
@@ -1422,7 +1577,7 @@ function useRagChat(projectId, options = {}) {
1422
1577
  const complete = buffer.slice(0, lastBoundary + 2);
1423
1578
  buffer = buffer.slice(lastBoundary + 2);
1424
1579
  for (const frame of parseSseChunk(complete)) {
1425
- if (frame.type === "text") {
1580
+ if (frame.type === "text" && frame.text) {
1426
1581
  assistantContent += frame.text;
1427
1582
  } else if (frame.type === "metadata") {
1428
1583
  sources = (_a = frame.sources) != null ? _a : [];
@@ -1444,7 +1599,7 @@ function useRagChat(projectId, options = {}) {
1444
1599
  }
1445
1600
  if (buffer.trim()) {
1446
1601
  for (const frame of parseSseChunk(buffer)) {
1447
- if (frame.type === "text") assistantContent += frame.text;
1602
+ if (frame.type === "text" && frame.text) assistantContent += frame.text;
1448
1603
  else if (frame.type === "metadata") sources = (_b = frame.sources) != null ? _b : [];
1449
1604
  }
1450
1605
  }
@@ -1467,12 +1622,12 @@ function useRagChat(projectId, options = {}) {
1467
1622
  },
1468
1623
  [apiUrl, isLoading, namespace, onError, onReply, projectId, setMessages]
1469
1624
  );
1470
- const clear = (0, import_react7.useCallback)(() => {
1625
+ const clear = (0, import_react8.useCallback)(() => {
1471
1626
  setMessages([]);
1472
1627
  setError(null);
1473
1628
  if (persist) localStorage.removeItem(storageKey);
1474
1629
  }, [persist, setMessages, storageKey]);
1475
- const retry = (0, import_react7.useCallback)(async () => {
1630
+ const retry = (0, import_react8.useCallback)(async () => {
1476
1631
  if (lastInputRef.current) {
1477
1632
  const latestMessage = messagesRef.current[messagesRef.current.length - 1];
1478
1633
  await sendMessage(lastInputRef.current, {
@@ -1506,20 +1661,20 @@ function ChatWindow({
1506
1661
  }) {
1507
1662
  var _a;
1508
1663
  const { ui, projectId } = useConfig();
1509
- const [input, setInput] = (0, import_react8.useState)("");
1510
- const [mounted, setMounted] = (0, import_react8.useState)(false);
1511
- const [viewportSize, setViewportSize] = (0, import_react8.useState)("large");
1512
- const windowRef = (0, import_react8.useRef)(null);
1513
- const bottomRef = (0, import_react8.useRef)(null);
1514
- const inputRef = (0, import_react8.useRef)(null);
1664
+ const [input, setInput] = (0, import_react9.useState)("");
1665
+ const [mounted, setMounted] = (0, import_react9.useState)(false);
1666
+ const [viewportSize, setViewportSize] = (0, import_react9.useState)("large");
1667
+ const windowRef = (0, import_react9.useRef)(null);
1668
+ const bottomRef = (0, import_react9.useRef)(null);
1669
+ const inputRef = (0, import_react9.useRef)(null);
1515
1670
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
1516
1671
  namespace: projectId
1517
1672
  });
1518
- const [suggestions, setSuggestions] = (0, import_react8.useState)([]);
1519
- const [isSuggesting, setIsSuggesting] = (0, import_react8.useState)(false);
1520
- const [isListening, setIsListening] = (0, import_react8.useState)(false);
1521
- const recognitionRef = (0, import_react8.useRef)(null);
1522
- (0, import_react8.useEffect)(() => {
1673
+ const [suggestions, setSuggestions] = (0, import_react9.useState)([]);
1674
+ const [isSuggesting, setIsSuggesting] = (0, import_react9.useState)(false);
1675
+ const [isListening, setIsListening] = (0, import_react9.useState)(false);
1676
+ const recognitionRef = (0, import_react9.useRef)(null);
1677
+ (0, import_react9.useEffect)(() => {
1523
1678
  if (typeof window !== "undefined") {
1524
1679
  const win = window;
1525
1680
  const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
@@ -1565,10 +1720,10 @@ function ChatWindow({
1565
1720
  }
1566
1721
  }
1567
1722
  };
1568
- (0, import_react8.useEffect)(() => {
1723
+ (0, import_react9.useEffect)(() => {
1569
1724
  setMounted(true);
1570
1725
  }, []);
1571
- (0, import_react8.useEffect)(() => {
1726
+ (0, import_react9.useEffect)(() => {
1572
1727
  const element = windowRef.current;
1573
1728
  if (!element || typeof ResizeObserver === "undefined") return;
1574
1729
  const resolveViewportSize = (width) => {
@@ -1584,13 +1739,13 @@ function ChatWindow({
1584
1739
  observer.observe(element);
1585
1740
  return () => observer.disconnect();
1586
1741
  }, []);
1587
- (0, import_react8.useEffect)(() => {
1742
+ (0, import_react9.useEffect)(() => {
1588
1743
  var _a2;
1589
1744
  if (messages.length > 0 || isLoading) {
1590
1745
  (_a2 = bottomRef.current) == null ? void 0 : _a2.scrollIntoView({ behavior: "smooth" });
1591
1746
  }
1592
1747
  }, [messages, isLoading]);
1593
- const sendMessage = (0, import_react8.useCallback)(async () => {
1748
+ const sendMessage = (0, import_react9.useCallback)(async () => {
1594
1749
  var _a2;
1595
1750
  const text = input.trim();
1596
1751
  if (!text || isLoading) return;
@@ -1620,7 +1775,7 @@ function ChatWindow({
1620
1775
  const isEmpty = messages.length === 0;
1621
1776
  const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
1622
1777
  const isGlass = ui.visualStyle !== "solid";
1623
- (0, import_react8.useEffect)(() => {
1778
+ (0, import_react9.useEffect)(() => {
1624
1779
  if (input.trim().length < 3) {
1625
1780
  return;
1626
1781
  }
@@ -1644,84 +1799,84 @@ function ChatWindow({
1644
1799
  }, 800);
1645
1800
  return () => clearTimeout(timer);
1646
1801
  }, [input, projectId]);
1647
- return /* @__PURE__ */ import_react8.default.createElement(
1802
+ return /* @__PURE__ */ import_react9.default.createElement(
1648
1803
  "div",
1649
1804
  {
1650
1805
  ref: windowRef,
1651
1806
  className: `relative flex flex-col border border-slate-200 dark:border-white/10 shadow-2xl transition-all duration-300 ${currentRadius} ${isGlass ? "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl" : "bg-white dark:bg-[#0f0f1a]"} ${className}`,
1652
1807
  style: __spreadValues({ "--primary": ui.primaryColor, "--accent": ui.accentColor }, style)
1653
1808
  },
1654
- onResizeStart && /* @__PURE__ */ import_react8.default.createElement(
1809
+ onResizeStart && /* @__PURE__ */ import_react9.default.createElement(
1655
1810
  "div",
1656
1811
  {
1657
1812
  onMouseDown: onResizeStart,
1658
1813
  className: "absolute top-0 left-0 w-6 h-6 cursor-nw-resize z-[100] group flex items-start justify-start p-1",
1659
1814
  title: "Drag to resize"
1660
1815
  },
1661
- /* @__PURE__ */ import_react8.default.createElement("div", { className: "w-2.5 h-2.5 border-t-2 border-l-2 border-slate-300 dark:border-white/20 group-hover:border-slate-500 dark:group-hover:border-white/50 transition-colors rounded-tl-[2px]" })
1816
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: "w-2.5 h-2.5 border-t-2 border-l-2 border-slate-300 dark:border-white/20 group-hover:border-slate-500 dark:group-hover:border-white/50 transition-colors rounded-tl-[2px]" })
1662
1817
  ),
1663
- /* @__PURE__ */ import_react8.default.createElement(
1818
+ /* @__PURE__ */ import_react9.default.createElement(
1664
1819
  "div",
1665
1820
  {
1666
1821
  className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-white/10",
1667
1822
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}15, ${ui.accentColor}10)` }
1668
1823
  },
1669
- /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
1824
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-3" }, ui.logoUrl ? (
1670
1825
  // eslint-disable-next-line @next/next/no-img-element
1671
- /* @__PURE__ */ import_react8.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
1672
- ) : /* @__PURE__ */ import_react8.default.createElement(
1826
+ /* @__PURE__ */ import_react9.default.createElement("img", { src: ui.logoUrl, alt: "logo", className: "w-8 h-8 rounded-lg object-cover" })
1827
+ ) : /* @__PURE__ */ import_react9.default.createElement(
1673
1828
  "div",
1674
1829
  {
1675
1830
  className: `w-9 h-9 flex items-center justify-center shadow-md ${ui.borderRadius === "full" ? "rounded-full" : "rounded-xl"}`,
1676
1831
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
1677
1832
  },
1678
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
1679
- ), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
1680
- /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5" }, mounted && messages.length > 0 && /* @__PURE__ */ import_react8.default.createElement(
1833
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Bot, { className: "w-5 h-5 text-white" })
1834
+ ), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("h2", { className: "text-slate-900 dark:text-white font-semibold text-sm leading-tight" }, ui.title), ui.poweredBy && /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-[11px] leading-tight" }, `Powered by ${ui.poweredBy}`))),
1835
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400 mr-2" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }), "Online"), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5" }, mounted && messages.length > 0 && /* @__PURE__ */ import_react9.default.createElement(
1681
1836
  "button",
1682
1837
  {
1683
1838
  onClick: clearHistory,
1684
1839
  title: "Clear conversation",
1685
1840
  className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-rose-500 dark:text-white/40 dark:hover:text-rose-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
1686
1841
  },
1687
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
1688
- ), isResized && onResetResize && /* @__PURE__ */ import_react8.default.createElement(
1842
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Trash2, { className: "w-3.5 h-3.5" })
1843
+ ), isResized && onResetResize && /* @__PURE__ */ import_react9.default.createElement(
1689
1844
  "button",
1690
1845
  {
1691
1846
  onClick: onResetResize,
1692
1847
  title: "Reset to default size",
1693
1848
  className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
1694
1849
  },
1695
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
1696
- ), onMaximize && /* @__PURE__ */ import_react8.default.createElement(
1850
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.RotateCcw, { className: "w-3.5 h-3.5" })
1851
+ ), onMaximize && /* @__PURE__ */ import_react9.default.createElement(
1697
1852
  "button",
1698
1853
  {
1699
1854
  onClick: onMaximize,
1700
1855
  title: isMaximized ? "Minimize" : "Maximize",
1701
1856
  className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-blue-500 dark:text-white/40 dark:hover:text-blue-400 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
1702
1857
  },
1703
- isMaximized ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
1704
- ), showClose && onClose && /* @__PURE__ */ import_react8.default.createElement(
1858
+ isMaximized ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Minimize2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Maximize2, { className: "w-3.5 h-3.5" })
1859
+ ), showClose && onClose && /* @__PURE__ */ import_react9.default.createElement(
1705
1860
  "button",
1706
1861
  {
1707
1862
  onClick: onClose,
1708
1863
  title: "Close chat",
1709
1864
  className: "w-7 h-7 rounded-md flex items-center justify-center text-slate-400 hover:text-slate-600 dark:text-white/40 dark:hover:text-white/70 hover:bg-white dark:hover:bg-white/10 transition-all cursor-pointer"
1710
1865
  },
1711
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
1866
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.X, { className: "w-4 h-4" })
1712
1867
  )))
1713
1868
  ),
1714
- /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent" }, !mounted || isEmpty ? (
1869
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex-1 overflow-y-auto px-4 py-4 space-y-5 scrollbar-thin scrollbar-thumb-slate-200 dark:scrollbar-thumb-white/10 scrollbar-track-transparent min-h-0 bg-slate-50 dark:bg-transparent" }, !mounted || isEmpty ? (
1715
1870
  /* Welcome state */
1716
- /* @__PURE__ */ import_react8.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react8.default.createElement(
1871
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: "h-full flex flex-col items-center justify-center text-center gap-4 px-6 py-12" }, /* @__PURE__ */ import_react9.default.createElement(
1717
1872
  "div",
1718
1873
  {
1719
1874
  className: `w-16 h-16 flex items-center justify-center shadow-lg ${ui.borderRadius === "full" ? "rounded-full" : "rounded-2xl"}`,
1720
1875
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` }
1721
1876
  },
1722
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
1723
- ), /* @__PURE__ */ import_react8.default.createElement("div", null, /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
1724
- (suggestion) => /* @__PURE__ */ import_react8.default.createElement(
1877
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-8 h-8 text-white" })
1878
+ ), /* @__PURE__ */ import_react9.default.createElement("div", null, /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-800 dark:text-white/80 font-medium leading-relaxed" }, ui.welcomeMessage), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-slate-500 dark:text-white/30 text-sm mt-2" }, "Ask a question to get started")), /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex flex-wrap gap-2 justify-center mt-2" }, CHAT_SUGGESTIONS.map(
1879
+ (suggestion) => /* @__PURE__ */ import_react9.default.createElement(
1725
1880
  "button",
1726
1881
  {
1727
1882
  key: suggestion,
@@ -1735,7 +1890,7 @@ function ChatWindow({
1735
1890
  suggestion
1736
1891
  )
1737
1892
  )))
1738
- ) : messages.map((msg, index) => /* @__PURE__ */ import_react8.default.createElement(
1893
+ ) : messages.map((msg, index) => /* @__PURE__ */ import_react9.default.createElement(
1739
1894
  MessageBubble,
1740
1895
  {
1741
1896
  key: msg.id,
@@ -1747,7 +1902,7 @@ function ChatWindow({
1747
1902
  onAddToCart,
1748
1903
  viewportSize
1749
1904
  }
1750
- )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react8.default.createElement(
1905
+ )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react9.default.createElement(
1751
1906
  MessageBubble,
1752
1907
  {
1753
1908
  message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
@@ -1757,8 +1912,8 @@ function ChatWindow({
1757
1912
  onAddToCart,
1758
1913
  viewportSize
1759
1914
  }
1760
- ), error && /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react8.default.createElement("span", null, error)), /* @__PURE__ */ import_react8.default.createElement("div", { ref: bottomRef })),
1761
- /* @__PURE__ */ import_react8.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react8.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react8.default.createElement(
1915
+ ), error && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-2 text-rose-500 dark:text-rose-400 text-sm bg-rose-50 dark:bg-rose-400/10 border border-rose-200 dark:border-rose-400/20 rounded-xl px-4 py-3" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.TriangleAlert, { className: "w-4 h-4 flex-shrink-0" }), /* @__PURE__ */ import_react9.default.createElement("span", null, error)), /* @__PURE__ */ import_react9.default.createElement("div", { ref: bottomRef })),
1916
+ /* @__PURE__ */ import_react9.default.createElement("div", { className: `px-4 pb-4 pt-2 border-t border-slate-200 dark:border-white/10 ${isGlass ? "bg-transparent" : "bg-white dark:bg-[#0f0f1a]"}` }, (suggestions.length > 0 || isSuggesting) && !isLoading && /* @__PURE__ */ import_react9.default.createElement("div", { className: "mb-3 flex flex-wrap gap-2 animate-in fade-in slide-in-from-bottom-2 duration-300" }, suggestions.map((suggestion) => /* @__PURE__ */ import_react9.default.createElement(
1762
1917
  "button",
1763
1918
  {
1764
1919
  key: suggestion,
@@ -1770,9 +1925,9 @@ function ChatWindow({
1770
1925
  },
1771
1926
  className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-600 dark:text-white/60 hover:text-slate-900 dark:hover:text-white/90 hover:border-slate-300 dark:hover:border-white/20 transition-all shadow-sm cursor-pointer group"
1772
1927
  },
1773
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
1928
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3 text-amber-400" }),
1774
1929
  suggestion
1775
- )), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react8.default.createElement("div", { className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium text-slate-400 dark:text-white/30 animate-pulse" }, /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react8.default.createElement("div", { className: `flex items-end gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 p-2 focus-within:border-slate-300 dark:focus-within:border-white/20 transition-all ${ui.borderRadius === "full" ? "rounded-3xl" : "rounded-2xl"}` }, /* @__PURE__ */ import_react8.default.createElement(
1930
+ )), isSuggesting && suggestions.length === 0 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-[11px] font-medium text-slate-400 dark:text-white/30 animate-pulse" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Sparkles, { className: "w-3 h-3" }), "Thinking...")), /* @__PURE__ */ import_react9.default.createElement("div", { className: `flex items-end gap-2 bg-slate-50 dark:bg-white/5 border border-slate-200 dark:border-white/10 p-2 focus-within:border-slate-300 dark:focus-within:border-white/20 transition-all ${ui.borderRadius === "full" ? "rounded-3xl" : "rounded-2xl"}` }, /* @__PURE__ */ import_react9.default.createElement(
1776
1931
  "textarea",
1777
1932
  {
1778
1933
  ref: inputRef,
@@ -1791,7 +1946,7 @@ function ChatWindow({
1791
1946
  className: "flex-1 bg-transparent text-slate-900 dark:text-white/90 placeholder-slate-400 dark:placeholder-white/30 text-sm resize-none outline-none py-1.5 px-2 max-h-32 leading-relaxed disabled:opacity-50",
1792
1947
  style: { scrollbarWidth: "none" }
1793
1948
  }
1794
- ), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react8.default.createElement(
1949
+ ), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react9.default.createElement(
1795
1950
  "button",
1796
1951
  {
1797
1952
  type: "button",
@@ -1800,8 +1955,8 @@ function ChatWindow({
1800
1955
  className: `flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:scale-100 disabled:active:scale-100 ${isListening ? "bg-rose-500 text-white animate-pulse shadow-md shadow-rose-500/20" : "text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10"}`,
1801
1956
  title: isListening ? "Stop listening" : "Start voice input"
1802
1957
  },
1803
- isListening ? /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
1804
- ), /* @__PURE__ */ import_react8.default.createElement(
1958
+ isListening ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
1959
+ ), /* @__PURE__ */ import_react9.default.createElement(
1805
1960
  "button",
1806
1961
  {
1807
1962
  onClick: sendMessage,
@@ -1812,8 +1967,8 @@ function ChatWindow({
1812
1967
  // slate-400/20 for light mode disabled
1813
1968
  }
1814
1969
  },
1815
- /* @__PURE__ */ import_react8.default.createElement(import_lucide_react5.ArrowUp, { className: "w-4 h-4 text-white" })
1816
- )), /* @__PURE__ */ import_react8.default.createElement("p", { className: "text-center text-[10px] text-slate-400 dark:text-white/20 mt-2" }, "Press Enter to send \xB7 Shift+Enter for new line"))
1970
+ /* @__PURE__ */ import_react9.default.createElement(import_lucide_react5.ArrowUp, { className: "w-4 h-4 text-white" })
1971
+ )), /* @__PURE__ */ import_react9.default.createElement("p", { className: "text-center text-[10px] text-slate-400 dark:text-white/20 mt-2" }, "Press Enter to send \xB7 Shift+Enter for new line"))
1817
1972
  );
1818
1973
  }
1819
1974
 
@@ -1821,12 +1976,12 @@ function ChatWindow({
1821
1976
  var DEFAULT_DIMENSIONS = { width: 380, height: 600 };
1822
1977
  function ChatWidget({ position = "bottom-right", onAddToCart }) {
1823
1978
  const { ui } = useConfig();
1824
- const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
1825
- const [hasUnread, setHasUnread] = (0, import_react9.useState)(false);
1826
- const [dimensions, setDimensions] = (0, import_react9.useState)(DEFAULT_DIMENSIONS);
1827
- const [isResizing, setIsResizing] = (0, import_react9.useState)(false);
1828
- const [isMaximized, setIsMaximized] = (0, import_react9.useState)(false);
1829
- const [prevDimensions, setPrevDimensions] = (0, import_react9.useState)(DEFAULT_DIMENSIONS);
1979
+ const [isOpen, setIsOpen] = (0, import_react10.useState)(false);
1980
+ const [hasUnread, setHasUnread] = (0, import_react10.useState)(false);
1981
+ const [dimensions, setDimensions] = (0, import_react10.useState)(DEFAULT_DIMENSIONS);
1982
+ const [isResizing, setIsResizing] = (0, import_react10.useState)(false);
1983
+ const [isMaximized, setIsMaximized] = (0, import_react10.useState)(false);
1984
+ const [prevDimensions, setPrevDimensions] = (0, import_react10.useState)(DEFAULT_DIMENSIONS);
1830
1985
  if (ui.showWidget === false) return null;
1831
1986
  const positionClass = position === "bottom-left" ? "bottom-6 left-6" : "bottom-6 right-6";
1832
1987
  const windowPositionClass = position === "bottom-left" ? "bottom-20 left-6" : "bottom-20 right-6";
@@ -1876,7 +2031,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
1876
2031
  }
1877
2032
  };
1878
2033
  const isResized = dimensions.width !== DEFAULT_DIMENSIONS.width || dimensions.height !== DEFAULT_DIMENSIONS.height;
1879
- return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(
2034
+ return /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(
1880
2035
  "div",
1881
2036
  {
1882
2037
  className: `fixed z-[9998] max-w-[calc(100vw-3rem)] ease-in-out ${windowPositionClass} ${isOpen ? "opacity-100 translate-y-0 pointer-events-auto" : "opacity-0 translate-y-4 pointer-events-none"} ${isResizing ? "" : "transition-all duration-300"}`,
@@ -1886,7 +2041,7 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
1886
2041
  maxHeight: "calc(100vh - 6rem)"
1887
2042
  }
1888
2043
  },
1889
- /* @__PURE__ */ import_react9.default.createElement(
2044
+ /* @__PURE__ */ import_react10.default.createElement(
1890
2045
  ChatWindow,
1891
2046
  {
1892
2047
  className: "h-full relative z-10",
@@ -1900,13 +2055,13 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
1900
2055
  onAddToCart
1901
2056
  }
1902
2057
  ),
1903
- /* @__PURE__ */ import_react9.default.createElement(
2058
+ /* @__PURE__ */ import_react10.default.createElement(
1904
2059
  "div",
1905
2060
  {
1906
2061
  className: `absolute -bottom-1.5 w-4 h-4 rotate-45 border-r border-b border-slate-200 dark:border-white/10 z-0 ${ui.visualStyle === "solid" ? "bg-white dark:bg-[#0f0f1a]" : "bg-white/90 dark:bg-[#0f0f1a]/90 backdrop-blur-xl"} ${position === "bottom-left" ? "left-5" : "right-5"}`
1907
2062
  }
1908
2063
  )
1909
- ), /* @__PURE__ */ import_react9.default.createElement(
2064
+ ), /* @__PURE__ */ import_react10.default.createElement(
1910
2065
  "button",
1911
2066
  {
1912
2067
  onClick: isOpen ? () => setIsOpen(false) : handleOpen,
@@ -1914,32 +2069,32 @@ function ChatWidget({ position = "bottom-right", onAddToCart }) {
1914
2069
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}, ${ui.accentColor})` },
1915
2070
  "aria-label": "Open chat"
1916
2071
  },
1917
- /* @__PURE__ */ import_react9.default.createElement(
2072
+ /* @__PURE__ */ import_react10.default.createElement(
1918
2073
  "span",
1919
2074
  {
1920
2075
  className: "absolute inset-0 rounded-full animate-ping opacity-20",
1921
2076
  style: { background: ui.primaryColor }
1922
2077
  }
1923
2078
  ),
1924
- /* @__PURE__ */ import_react9.default.createElement(
2079
+ /* @__PURE__ */ import_react10.default.createElement(
1925
2080
  "span",
1926
2081
  {
1927
2082
  className: `transition-transform duration-300 ${isOpen ? "rotate-90 scale-90" : "rotate-0 scale-100"}`
1928
2083
  },
1929
- isOpen ? /* @__PURE__ */ import_react9.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react9.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
2084
+ isOpen ? /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.X, { className: "w-6 h-6 text-white" }) : /* @__PURE__ */ import_react10.default.createElement(import_lucide_react6.MessageSquare, { className: "w-6 h-6 text-white" })
1930
2085
  ),
1931
- hasUnread && !isOpen && /* @__PURE__ */ import_react9.default.createElement("span", { className: "absolute top-0 right-0 w-4 h-4 bg-rose-500 rounded-full border-2 border-white flex items-center justify-center text-[9px] font-bold text-white" }, "1")
2086
+ hasUnread && !isOpen && /* @__PURE__ */ import_react10.default.createElement("span", { className: "absolute top-0 right-0 w-4 h-4 bg-rose-500 rounded-full border-2 border-white flex items-center justify-center text-[9px] font-bold text-white" }, "1")
1932
2087
  ));
1933
2088
  }
1934
2089
 
1935
2090
  // src/components/DocumentUpload.tsx
1936
- var import_react10 = __toESM(require("react"));
2091
+ var import_react11 = __toESM(require("react"));
1937
2092
  var import_lucide_react7 = require("lucide-react");
1938
2093
  function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
1939
2094
  const { ui } = useConfig();
1940
- const [fileStates, setFileStates] = (0, import_react10.useState)([]);
1941
- const [isDragging, setIsDragging] = (0, import_react10.useState)(false);
1942
- const fileInputRef = (0, import_react10.useRef)(null);
2095
+ const [fileStates, setFileStates] = (0, import_react11.useState)([]);
2096
+ const [isDragging, setIsDragging] = (0, import_react11.useState)(false);
2097
+ const fileInputRef = (0, import_react11.useRef)(null);
1943
2098
  const addFiles = (files) => {
1944
2099
  const newStates = files.map((file) => ({ file, status: "idle" }));
1945
2100
  setFileStates((prev) => [...prev, ...newStates]);
@@ -1989,7 +2144,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
1989
2144
  };
1990
2145
  const isUploading = fileStates.some((s) => s.status === "uploading");
1991
2146
  const hasIdle = fileStates.some((s) => s.status === "idle");
1992
- return /* @__PURE__ */ import_react10.default.createElement(
2147
+ return /* @__PURE__ */ import_react11.default.createElement(
1993
2148
  "div",
1994
2149
  {
1995
2150
  className: `p-6 border-2 border-dashed transition-all duration-300 rounded-2xl ${isDragging ? "border-emerald-500 bg-emerald-50/50 dark:bg-emerald-500/5" : "border-slate-200 dark:border-white/10 bg-white dark:bg-white/5"} ${className}`,
@@ -1997,14 +2152,14 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
1997
2152
  onDragLeave,
1998
2153
  onDrop
1999
2154
  },
2000
- /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react10.default.createElement(
2155
+ /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex flex-col items-center justify-center text-center" }, /* @__PURE__ */ import_react11.default.createElement(
2001
2156
  "div",
2002
2157
  {
2003
2158
  className: "w-12 h-12 rounded-full flex items-center justify-center mb-4 shadow-sm",
2004
2159
  style: { background: `linear-gradient(135deg, ${ui.primaryColor}20, ${ui.accentColor}20)` }
2005
2160
  },
2006
- /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
2007
- ), /* @__PURE__ */ import_react10.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-sm mb-6 max-w-xs" }, "Drag and drop PDF, DOCX, TXT, or JSON files to train your AI on your own data."), /* @__PURE__ */ import_react10.default.createElement(
2161
+ /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Upload, { className: "w-6 h-6", style: { color: ui.primaryColor } })
2162
+ ), /* @__PURE__ */ import_react11.default.createElement("h3", { className: "text-slate-900 dark:text-white font-semibold mb-1" }, "Upload Documents"), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-slate-500 dark:text-white/40 text-sm mb-6 max-w-xs" }, "Drag and drop PDF, DOCX, TXT, or JSON files to train your AI on your own data."), /* @__PURE__ */ import_react11.default.createElement(
2008
2163
  "button",
2009
2164
  {
2010
2165
  onClick: () => {
@@ -2020,7 +2175,7 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
2020
2175
  }
2021
2176
  },
2022
2177
  "Select Files"
2023
- ), /* @__PURE__ */ import_react10.default.createElement(
2178
+ ), /* @__PURE__ */ import_react11.default.createElement(
2024
2179
  "input",
2025
2180
  {
2026
2181
  ref: fileInputRef,
@@ -2031,22 +2186,22 @@ function DocumentUpload({ namespace, onUploadComplete, className = "" }) {
2031
2186
  accept: ".pdf,.docx,.txt,.md,.json,.csv"
2032
2187
  }
2033
2188
  )),
2034
- fileStates.length > 0 && /* @__PURE__ */ import_react10.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react10.default.createElement(
2189
+ fileStates.length > 0 && /* @__PURE__ */ import_react11.default.createElement("div", { className: "mt-8 space-y-3" }, fileStates.map((state, i) => /* @__PURE__ */ import_react11.default.createElement(
2035
2190
  "div",
2036
2191
  {
2037
2192
  key: i,
2038
2193
  className: "flex items-center justify-between p-3 rounded-xl bg-slate-50 dark:bg-white/5 border border-slate-100 dark:border-white/10"
2039
2194
  },
2040
- /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "w-8 h-8 rounded-lg bg-white dark:bg-white/10 flex items-center justify-center shadow-sm" }, /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react10.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react10.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
2041
- /* @__PURE__ */ import_react10.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react10.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react10.default.createElement(
2195
+ /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-3 overflow-hidden" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "w-8 h-8 rounded-lg bg-white dark:bg-white/10 flex items-center justify-center shadow-sm" }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.File, { className: "w-4 h-4 text-slate-400" })), /* @__PURE__ */ import_react11.default.createElement("div", { className: "truncate" }, /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-xs font-medium text-slate-700 dark:text-white/80 truncate" }, state.file.name), /* @__PURE__ */ import_react11.default.createElement("p", { className: "text-[10px] text-slate-400" }, (state.file.size / 1024).toFixed(1), " KB"))),
2196
+ /* @__PURE__ */ import_react11.default.createElement("div", { className: "flex items-center gap-2" }, state.status === "uploading" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.Loader2, { className: "w-4 h-4 text-slate-400 animate-spin" }), state.status === "success" && /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.CheckCircle, { className: "w-4 h-4 text-emerald-500" }), state.status === "error" && /* @__PURE__ */ import_react11.default.createElement("div", { title: state.error }, /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.AlertCircle, { className: "w-4 h-4 text-rose-500" })), state.status !== "uploading" && /* @__PURE__ */ import_react11.default.createElement(
2042
2197
  "button",
2043
2198
  {
2044
2199
  onClick: () => removeFile(i),
2045
2200
  className: "p-1 rounded-md hover:bg-slate-200 dark:hover:bg-white/10 transition-colors"
2046
2201
  },
2047
- /* @__PURE__ */ import_react10.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
2202
+ /* @__PURE__ */ import_react11.default.createElement(import_lucide_react7.X, { className: "w-3.5 h-3.5 text-slate-400" })
2048
2203
  ))
2049
- )), hasIdle && !isUploading && /* @__PURE__ */ import_react10.default.createElement(
2204
+ )), hasIdle && !isUploading && /* @__PURE__ */ import_react11.default.createElement(
2050
2205
  "button",
2051
2206
  {
2052
2207
  onClick: uploadFiles,