reachat 2.2.0 → 3.1.0

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 (46) hide show
  1. package/dist/{CSVFileRenderer-BOdL4Jte.js → CSVFileRenderer-C2E4Xnkz.js} +2 -2
  2. package/dist/{CSVFileRenderer-BOdL4Jte.js.map → CSVFileRenderer-C2E4Xnkz.js.map} +1 -1
  3. package/dist/Chat.d.ts +12 -0
  4. package/dist/{Markdown/charts/ChartError.d.ts → ComponentCatalog/ComponentError.d.ts} +2 -2
  5. package/dist/ComponentCatalog/ComponentPre.d.ts +18 -0
  6. package/dist/ComponentCatalog/ComponentRenderer.d.ts +17 -0
  7. package/dist/ComponentCatalog/chartComponentDef.d.ts +36 -0
  8. package/dist/ComponentCatalog/componentCatalog.d.ts +44 -0
  9. package/dist/ComponentCatalog/componentCatalog.spec.d.ts +1 -0
  10. package/dist/ComponentCatalog/generatePrompt.d.ts +9 -0
  11. package/dist/ComponentCatalog/generatePrompt.spec.d.ts +1 -0
  12. package/dist/ComponentCatalog/index.d.ts +9 -0
  13. package/dist/ComponentCatalog/types.d.ts +108 -0
  14. package/dist/ComponentCatalog/validateSpec.d.ts +17 -0
  15. package/dist/ComponentCatalog/validateSpec.spec.d.ts +1 -0
  16. package/dist/{DefaultFileRenderer-C2MsQ9wz.js → DefaultFileRenderer-Day12qYs.js} +2 -2
  17. package/dist/{DefaultFileRenderer-C2MsQ9wz.js.map → DefaultFileRenderer-Day12qYs.js.map} +1 -1
  18. package/dist/Markdown/charts/ChartRenderer.d.ts +1 -1
  19. package/dist/Markdown/charts/ComponentError.d.ts +1 -0
  20. package/dist/Markdown/charts/index.d.ts +2 -6
  21. package/dist/Markdown/charts/types.d.ts +21 -0
  22. package/dist/Markdown/plugins/index.d.ts +1 -1
  23. package/dist/Markdown/plugins/remarkComponent.d.ts +27 -0
  24. package/dist/docs.json +275 -93
  25. package/dist/{index-DdRyk11n.js → index-CZSBRZbI.js} +524 -230
  26. package/dist/index-CZSBRZbI.js.map +1 -0
  27. package/dist/index.css +101 -1077
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +22 -22
  30. package/dist/index.umd.cjs +509 -215
  31. package/dist/index.umd.cjs.map +1 -1
  32. package/dist/stories/Changelog.mdx +1 -1
  33. package/dist/stories/Charts.stories.tsx +118 -130
  34. package/dist/stories/ComponentCatalog.stories.tsx +509 -0
  35. package/dist/stories/{ChartError.stories.tsx → ComponentError.stories.tsx} +14 -11
  36. package/dist/stories/Intro.mdx +1 -1
  37. package/dist/theme.d.ts +3 -0
  38. package/dist/utils/getChildText.d.ts +10 -0
  39. package/dist/utils/getChildText.spec.d.ts +1 -0
  40. package/package.json +27 -30
  41. package/dist/Markdown/charts/ChartPre.d.ts +0 -6
  42. package/dist/Markdown/charts/chartHelpers.d.ts +0 -40
  43. package/dist/Markdown/plugins/remarkChart.d.ts +0 -59
  44. package/dist/index-DdRyk11n.js.map +0 -1
  45. package/dist/stories/Integration.stories.tsx +0 -312
  46. /package/dist/{Markdown/charts/chartHelpers.spec.d.ts → ComponentCatalog/chartComponentDef.spec.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
- import { createContext, useContext, useRef, forwardRef, useState, useEffect, useCallback, useImperativeHandle, memo, useMemo, lazy, Suspense, isValidElement, cloneElement } from "react";
3
+ import { createContext, useContext, useRef, forwardRef, useState, useEffect, useCallback, useImperativeHandle, memo, useMemo, lazy, Suspense, isValidElement, cloneElement, Component } from "react";
4
4
  import { Button, cn, List, ListItem, Ellipsis, DateFormat, Redact, IconButton, Card, useInfinityList, useComponentTheme, ConnectedOverlay } from "reablocks";
5
5
  import { useEditor, EditorContent, ReactRenderer, posToDOMRect } from "@tiptap/react";
6
6
  import { computePosition, shift, flip } from "@floating-ui/dom";
@@ -18,7 +18,6 @@ import rehypeKatex from "rehype-katex";
18
18
  import rehypeRaw from "rehype-raw";
19
19
  import { SparklineChart, RadialAreaChart, RadialAreaSeries, RadialBarChart, RadialBarSeries, PieChart, PieArcSeries, AreaChart, AreaSeries, LinearYAxis, LinearXAxis, LineChart, LineSeries, BarChart, BarSeries } from "reaviz";
20
20
  import { findAndReplace } from "mdast-util-find-and-replace";
21
- import { visit } from "unist-util-visit";
22
21
  import debounce from "lodash/debounce.js";
23
22
  import { useHotkeys } from "reakeys";
24
23
  import remarkGfm from "remark-gfm";
@@ -26,6 +25,7 @@ import remarkYoutube from "remark-youtube";
26
25
  import remarkMath from "remark-math";
27
26
  import { isToday, isYesterday, isThisWeek, differenceInYears, format } from "date-fns";
28
27
  import { offset } from "@floating-ui/react";
28
+ import { z } from "zod";
29
29
  const SvgSend = (props) => /* @__PURE__ */ React.createElement("svg", { width: 17, height: 17, viewBox: "0 0 17 17", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props }, /* @__PURE__ */ React.createElement("g", { id: "send" }, /* @__PURE__ */ React.createElement("path", { id: "Vector", d: "M14.6111 2.33327C14.5349 2.3339 14.4598 2.35194 14.3917 2.386L2.39168 8.386C2.31456 8.42456 2.24872 8.4824 2.20055 8.55391C2.15238 8.62543 2.12352 8.70818 2.11677 8.79414C2.11002 8.88009 2.12561 8.96634 2.16203 9.04449C2.19845 9.12264 2.25446 9.19005 2.32462 9.24017L4.52514 10.8124L5.47371 13.6581C5.50257 13.7447 5.55457 13.8217 5.62406 13.8808C5.69355 13.9399 5.7779 13.9789 5.86796 13.9935C5.95802 14.0082 6.05036 13.9979 6.13499 13.9638C6.21962 13.9297 6.2933 13.873 6.34806 13.8001L7.05249 12.8606L10.3207 15.2376C10.3843 15.2839 10.4579 15.3146 10.5355 15.3271C10.6132 15.3396 10.6927 15.3336 10.7676 15.3097C10.8425 15.2857 10.9107 15.2444 10.9667 15.1891C11.0226 15.1338 11.0647 15.0661 11.0896 14.9915L15.0896 2.99147C15.1148 2.91597 15.1216 2.83555 15.1094 2.7569C15.0972 2.67825 15.0665 2.60363 15.0197 2.53926C14.9729 2.47488 14.9114 2.42261 14.8403 2.38678C14.7693 2.35096 14.6907 2.33261 14.6111 2.33327ZM13.2478 5.35345L10.3565 14.0266L7.67293 12.0755L13.2478 5.35345ZM10.684 5.35801L4.934 9.87559L3.58113 8.90879L10.684 5.35801ZM11.2784 6.16205L6.56746 11.843C6.56681 11.8437 6.56616 11.8443 6.56551 11.845L6.56355 11.8476C6.55841 11.8538 6.55342 11.8601 6.54858 11.8665C6.54319 11.8733 6.53798 11.8802 6.53295 11.8873L6.12085 12.4361L5.53426 10.6751L11.2784 6.16205Z", fill: "currentColor" })));
30
30
  const SvgStop = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 24, height: 24, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 1, strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-octagon-x", ...props }, /* @__PURE__ */ React.createElement("path", { d: "m15 9-6 6" }), /* @__PURE__ */ React.createElement("path", { d: "M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z" }), /* @__PURE__ */ React.createElement("path", { d: "m9 9 6 6" }));
31
31
  const ChatContext = createContext({
@@ -65,10 +65,7 @@ const FileInput = ({
65
65
  variant: "text",
66
66
  disabled: isLoading || disabled,
67
67
  className: cn(theme.input.upload),
68
- onClick: () => {
69
- var _a;
70
- return (_a = fileInputRef.current) == null ? void 0 : _a.click();
71
- },
68
+ onClick: () => fileInputRef.current?.click(),
72
69
  children: attachIcon
73
70
  }
74
71
  )
@@ -315,23 +312,24 @@ const chatTheme = {
315
312
  ].join(" "),
316
313
  title: "text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-2"
317
314
  }
315
+ },
316
+ component: {
317
+ base: "my-4"
318
318
  }
319
319
  };
320
320
  const POPUP_STYLE = { zIndex: 9999 };
321
321
  const MentionList = forwardRef(
322
322
  ({ items, command, triggerChar, config, query }, ref) => {
323
- var _a;
324
323
  const [selectedIndex, setSelectedIndex] = useState(0);
325
324
  const itemRefs = useRef([]);
326
325
  const { theme } = useContext(ChatContext);
327
- const popupTheme = ((_a = theme == null ? void 0 : theme.input) == null ? void 0 : _a.popup) || chatTheme.input.popup;
326
+ const popupTheme = theme?.input?.popup || chatTheme.input.popup;
328
327
  useEffect(() => {
329
328
  setSelectedIndex(0);
330
329
  }, [items]);
331
330
  useEffect(() => {
332
- var _a2;
333
331
  if (itemRefs.current[selectedIndex]) {
334
- (_a2 = itemRefs.current[selectedIndex]) == null ? void 0 : _a2.scrollIntoView({
332
+ itemRefs.current[selectedIndex]?.scrollIntoView({
335
333
  block: "nearest",
336
334
  behavior: "smooth"
337
335
  });
@@ -462,10 +460,7 @@ function createSuggestionConfig(config, triggerChar, suggestionActiveRef) {
462
460
  if (!query) return config.items.slice(0, config.maxResults || 10);
463
461
  const lowerQuery = query.toLowerCase();
464
462
  return config.items.filter(
465
- (item) => {
466
- var _a;
467
- return item.label.toLowerCase().includes(lowerQuery) || ((_a = item.description) == null ? void 0 : _a.toLowerCase().includes(lowerQuery));
468
- }
463
+ (item) => item.label.toLowerCase().includes(lowerQuery) || item.description?.toLowerCase().includes(lowerQuery)
469
464
  ).slice(0, config.maxResults || 10);
470
465
  },
471
466
  // Render callbacks for managing the popup lifecycle
@@ -492,7 +487,7 @@ function createSuggestionConfig(config, triggerChar, suggestionActiveRef) {
492
487
  },
493
488
  // Called when query or items change
494
489
  onUpdate: (props) => {
495
- component == null ? void 0 : component.updateProps({
490
+ component?.updateProps({
496
491
  ...props,
497
492
  triggerChar,
498
493
  config
@@ -500,25 +495,23 @@ function createSuggestionConfig(config, triggerChar, suggestionActiveRef) {
500
495
  if (!props.clientRect) {
501
496
  return;
502
497
  }
503
- if (component == null ? void 0 : component.element) {
498
+ if (component?.element) {
504
499
  updatePopupPosition(props.editor, component.element);
505
500
  }
506
501
  },
507
502
  // Handle keyboard navigation (Escape closes popup)
508
503
  onKeyDown: (props) => {
509
- var _a;
510
504
  if (props.event.key === "Escape") {
511
- component == null ? void 0 : component.destroy();
505
+ component?.destroy();
512
506
  return true;
513
507
  }
514
- return ((_a = component == null ? void 0 : component.ref) == null ? void 0 : _a.onKeyDown(props)) ?? false;
508
+ return component?.ref?.onKeyDown(props) ?? false;
515
509
  },
516
510
  // Cleanup when suggestion is dismissed
517
511
  onExit: () => {
518
- var _a;
519
512
  suggestionActiveRef.current = false;
520
- (_a = component == null ? void 0 : component.element) == null ? void 0 : _a.remove();
521
- component == null ? void 0 : component.destroy();
513
+ component?.element?.remove();
514
+ component?.destroy();
522
515
  }
523
516
  };
524
517
  }
@@ -538,12 +531,10 @@ const RichTextInput = forwardRef(
538
531
  onSubmit,
539
532
  onChange
540
533
  }, ref) => {
541
- var _a, _b, _c, _d;
542
534
  const { theme } = useContext(ChatContext);
543
535
  const containerRef = useRef(null);
544
536
  const suggestionActiveRef = useRef(false);
545
537
  const extensions = useMemo(() => {
546
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h;
547
538
  const exts = [
548
539
  Document,
549
540
  Paragraph.configure({
@@ -562,7 +553,7 @@ const RichTextInput = forwardRef(
562
553
  exts.push(
563
554
  Mention.configure({
564
555
  HTMLAttributes: {
565
- class: cn((_b2 = (_a2 = theme == null ? void 0 : theme.input) == null ? void 0 : _a2.tag) == null ? void 0 : _b2.base, (_d2 = (_c2 = theme == null ? void 0 : theme.input) == null ? void 0 : _c2.tag) == null ? void 0 : _d2.mention)
556
+ class: cn(theme?.input?.tag?.base, theme?.input?.tag?.mention)
566
557
  },
567
558
  suggestion: createSuggestionConfig(
568
559
  mentions,
@@ -578,7 +569,7 @@ const RichTextInput = forwardRef(
578
569
  exts.push(
579
570
  Mention.configure({
580
571
  HTMLAttributes: {
581
- class: cn((_f = (_e = theme == null ? void 0 : theme.input) == null ? void 0 : _e.tag) == null ? void 0 : _f.base, (_h = (_g = theme == null ? void 0 : theme.input) == null ? void 0 : _g.tag) == null ? void 0 : _h.command)
572
+ class: cn(theme?.input?.tag?.base, theme?.input?.tag?.command)
582
573
  },
583
574
  suggestion: createSuggestionConfig(
584
575
  commands,
@@ -599,13 +590,13 @@ const RichTextInput = forwardRef(
599
590
  immediatelyRender: false,
600
591
  onUpdate: ({ editor: editor2 }) => {
601
592
  const text = editor2.getText();
602
- onChange == null ? void 0 : onChange(text);
593
+ onChange?.(text);
603
594
  },
604
595
  editorProps: {
605
596
  attributes: {
606
597
  class: cn(
607
- (_b = (_a = theme == null ? void 0 : theme.input) == null ? void 0 : _a.editor) == null ? void 0 : _b.base,
608
- (_d = (_c = theme == null ? void 0 : theme.input) == null ? void 0 : _c.editor) == null ? void 0 : _d.placeholder
598
+ theme?.input?.editor?.base,
599
+ theme?.input?.editor?.placeholder
609
600
  ),
610
601
  style: `min-height: ${minHeight}px; max-height: ${maxHeight}px;`,
611
602
  role: "textbox",
@@ -623,7 +614,7 @@ const RichTextInput = forwardRef(
623
614
  if (text.trim() && onSubmit) {
624
615
  event.preventDefault();
625
616
  onSubmit(text);
626
- editor == null ? void 0 : editor.commands.clearContent();
617
+ editor?.commands.clearContent();
627
618
  return true;
628
619
  }
629
620
  }
@@ -640,16 +631,16 @@ const RichTextInput = forwardRef(
640
631
  }, [editor, autoFocus]);
641
632
  useImperativeHandle(ref, () => ({
642
633
  focus: () => {
643
- editor == null ? void 0 : editor.commands.focus();
634
+ editor?.commands.focus();
644
635
  },
645
636
  getValue: () => {
646
- return (editor == null ? void 0 : editor.getText()) || "";
637
+ return editor?.getText() || "";
647
638
  },
648
639
  setValue: (newValue) => {
649
- editor == null ? void 0 : editor.commands.setContent(newValue ? `<p>${newValue}</p>` : "");
640
+ editor?.commands.setContent(newValue ? `<p>${newValue}</p>` : "");
650
641
  },
651
642
  insertText: (text) => {
652
- editor == null ? void 0 : editor.commands.insertContent(text);
643
+ editor?.commands.insertContent(text);
653
644
  }
654
645
  }));
655
646
  return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("relative w-full", className), children: /* @__PURE__ */ jsx(EditorContent, { editor }) });
@@ -683,43 +674,37 @@ const ChatInput = forwardRef(
683
674
  const inputRef = useRef(null);
684
675
  const containerRef = useRef(null);
685
676
  useEffect(() => {
686
- var _a;
687
677
  if (autoFocus) {
688
- (_a = inputRef.current) == null ? void 0 : _a.focus();
678
+ inputRef.current?.focus();
689
679
  }
690
680
  }, [activeSessionId, autoFocus]);
691
681
  useImperativeHandle(ref, () => ({
692
682
  focus: () => {
693
- var _a;
694
- (_a = inputRef.current) == null ? void 0 : _a.focus();
683
+ inputRef.current?.focus();
695
684
  },
696
685
  getValue: () => {
697
- var _a;
698
- return ((_a = inputRef.current) == null ? void 0 : _a.getValue()) || "";
686
+ return inputRef.current?.getValue() || "";
699
687
  },
700
688
  setValue: (value) => {
701
- var _a;
702
689
  setMessage(value);
703
- (_a = inputRef.current) == null ? void 0 : _a.setValue(value);
690
+ inputRef.current?.setValue(value);
704
691
  },
705
692
  insertText: (text) => {
706
- var _a;
707
- (_a = inputRef.current) == null ? void 0 : _a.insertText(text);
693
+ inputRef.current?.insertText(text);
708
694
  }
709
695
  }));
710
696
  const handleSendMessage = useCallback(() => {
711
- var _a, _b;
712
- const currentMessage = (_a = inputRef.current) == null ? void 0 : _a.getValue();
697
+ const currentMessage = inputRef.current?.getValue();
713
698
  if (currentMessage.trim()) {
714
- sendMessage == null ? void 0 : sendMessage(currentMessage);
699
+ sendMessage?.(currentMessage);
715
700
  setMessage("");
716
- (_b = inputRef.current) == null ? void 0 : _b.setValue("");
701
+ inputRef.current?.setValue("");
717
702
  }
718
703
  }, [sendMessage]);
719
704
  const handleSubmit = useCallback(
720
705
  (value) => {
721
706
  if (value.trim()) {
722
- sendMessage == null ? void 0 : sendMessage(value);
707
+ sendMessage?.(value);
723
708
  setMessage("");
724
709
  }
725
710
  },
@@ -730,8 +715,7 @@ const ChatInput = forwardRef(
730
715
  }, []);
731
716
  const handleFileUpload = useCallback(
732
717
  (event) => {
733
- var _a;
734
- const file = (_a = event.target.files) == null ? void 0 : _a[0];
718
+ const file = event.target.files?.[0];
735
719
  if (file && fileUpload) {
736
720
  fileUpload(file);
737
721
  }
@@ -765,7 +749,7 @@ const ChatInput = forwardRef(
765
749
  }
766
750
  ),
767
751
  /* @__PURE__ */ jsxs("div", { className: cn(theme.input.actions.base), children: [
768
- (allowedFiles == null ? void 0 : allowedFiles.length) > 0 && /* @__PURE__ */ jsx(
752
+ allowedFiles?.length > 0 && /* @__PURE__ */ jsx(
769
753
  FileInput,
770
754
  {
771
755
  allowedFiles,
@@ -1875,7 +1859,7 @@ const CodeHighlighter = ({
1875
1859
  toolbarClassName,
1876
1860
  theme = dark
1877
1861
  }) => {
1878
- const match = language == null ? void 0 : language.match(/language-(\w+)/);
1862
+ const match = language?.match(/language-(\w+)/);
1879
1863
  const lang = match ? match[1] : "text";
1880
1864
  const handleCopy = (text) => {
1881
1865
  navigator.clipboard.writeText(text).then(() => {
@@ -1958,14 +1942,16 @@ const Markdown = ({
1958
1942
  li: (props) => /* @__PURE__ */ jsx("li", { ...props, className: cn(theme.messages.message.markdown.li) }),
1959
1943
  ul: (props) => /* @__PURE__ */ jsx("ul", { ...props, className: cn(theme.messages.message.markdown.ul) }),
1960
1944
  ol: (props) => /* @__PURE__ */ jsx("ol", { ...props, className: cn(theme.messages.message.markdown.ol) }),
1961
- redact: (props) => /* @__PURE__ */ jsx(
1945
+ // 'redact' is a custom element created by remarkRedact, not a standard
1946
+ // HTML tag, so it falls outside react-markdown's Components type.
1947
+ redact: ((props) => /* @__PURE__ */ jsx(
1962
1948
  Redact,
1963
1949
  {
1964
1950
  value: props["data-redact-value"] || props.children,
1965
1951
  allowToggle: true,
1966
1952
  tooltipText: `${props["data-redact-name"] || "Sensitive"} information - Click to toggle`
1967
1953
  }
1968
- )
1954
+ ))
1969
1955
  };
1970
1956
  return {
1971
1957
  ...defaultComponents,
@@ -1983,7 +1969,7 @@ const Markdown = ({
1983
1969
  }
1984
1970
  );
1985
1971
  };
1986
- const ChartError = ({
1972
+ const ComponentError = ({
1987
1973
  variant = "error",
1988
1974
  title,
1989
1975
  message,
@@ -2011,12 +1997,12 @@ const ChartRenderer = ({
2011
1997
  data: d.data
2012
1998
  }));
2013
1999
  if (!chartData || chartData.length === 0) {
2014
- return /* @__PURE__ */ jsx(ChartError, { variant: "warning", message: "No chart data available" });
2000
+ return /* @__PURE__ */ jsx(ComponentError, { variant: "warning", message: "No chart data available" });
2015
2001
  }
2016
2002
  for (const point of chartData) {
2017
2003
  if (typeof point.data !== "number" || isNaN(point.data)) {
2018
2004
  return /* @__PURE__ */ jsx(
2019
- ChartError,
2005
+ ComponentError,
2020
2006
  {
2021
2007
  message: `Invalid data point: ${JSON.stringify(point)}`
2022
2008
  }
@@ -2085,10 +2071,10 @@ const ChartRenderer = ({
2085
2071
  case "sparkline":
2086
2072
  return /* @__PURE__ */ jsx(SparklineChart, { width, height, data: chartData });
2087
2073
  default:
2088
- return /* @__PURE__ */ jsx(ChartError, { message: `Unknown chart type: ${type}` });
2074
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Unknown chart type: ${type}` });
2089
2075
  }
2090
2076
  } catch (error) {
2091
- return /* @__PURE__ */ jsx(ChartError, { message: `Chart render error: ${String(error)}` });
2077
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Chart render error: ${String(error)}` });
2092
2078
  }
2093
2079
  }, [type, data, width, height]);
2094
2080
  return /* @__PURE__ */ jsxs("div", { className: cn(theme.chart.base, className), children: [
@@ -2096,93 +2082,6 @@ const ChartRenderer = ({
2096
2082
  /* @__PURE__ */ jsx("div", { className: theme.chart.content, children: chartElement })
2097
2083
  ] });
2098
2084
  };
2099
- function validateChartData(data) {
2100
- if (!Array.isArray(data)) {
2101
- return null;
2102
- }
2103
- const validData = [];
2104
- for (const item of data) {
2105
- if (item && typeof item === "object" && "key" in item && "data" in item && typeof item.data === "number") {
2106
- validData.push({
2107
- key: String(item.key),
2108
- data: item.data
2109
- });
2110
- } else {
2111
- return null;
2112
- }
2113
- }
2114
- return validData.length > 0 ? validData : null;
2115
- }
2116
- function parseChartConfig(value) {
2117
- try {
2118
- const config = JSON.parse(value);
2119
- if (!config || !config.type || !config.data) {
2120
- return null;
2121
- }
2122
- const validData = validateChartData(config.data);
2123
- if (!validData) {
2124
- console.warn("parseChartConfig: Invalid chart data format");
2125
- return null;
2126
- }
2127
- return {
2128
- ...config,
2129
- data: validData
2130
- };
2131
- } catch (error) {
2132
- console.warn("parseChartConfig: Failed to parse JSON", error);
2133
- return null;
2134
- }
2135
- }
2136
- function isChartClassName(className) {
2137
- return className === "language-chart";
2138
- }
2139
- function getChildText(children) {
2140
- if (children === null || children === void 0) {
2141
- return "";
2142
- }
2143
- if (typeof children === "string") {
2144
- return children;
2145
- }
2146
- if (typeof children === "number") {
2147
- return String(children);
2148
- }
2149
- if (Array.isArray(children)) {
2150
- return children.map(getChildText).join("");
2151
- }
2152
- if (typeof children === "object") {
2153
- if ("props" in children && children.props) {
2154
- const element = children;
2155
- return getChildText(element.props.children);
2156
- }
2157
- }
2158
- return "";
2159
- }
2160
- const ChartPre = ({ children, ...props }) => {
2161
- var _a, _b;
2162
- if (children && typeof children === "object" && "props" in children) {
2163
- const codeElement = children;
2164
- if (isChartClassName((_a = codeElement.props) == null ? void 0 : _a.className)) {
2165
- const codeContent = getChildText((_b = codeElement.props) == null ? void 0 : _b.children);
2166
- if (codeContent) {
2167
- const chartConfig = parseChartConfig(codeContent);
2168
- if (chartConfig) {
2169
- return /* @__PURE__ */ jsx(ChartRenderer, { config: chartConfig });
2170
- }
2171
- }
2172
- return /* @__PURE__ */ jsx(
2173
- ChartError,
2174
- {
2175
- title: "Failed to parse chart configuration",
2176
- code: codeContent || "No content"
2177
- }
2178
- );
2179
- }
2180
- }
2181
- return /* @__PURE__ */ jsx("pre", { ...props, children });
2182
- };
2183
- const chartComponents = {
2184
- pre: ChartPre
2185
- };
2186
2085
  const CVE_REGEX = /(CVE-(19|20)\d{2}-\d{4,7})/gi;
2187
2086
  function remarkCve() {
2188
2087
  return (tree, _file) => {
@@ -2203,31 +2102,8 @@ function remarkCve() {
2203
2102
  ];
2204
2103
  }
2205
2104
  }
2206
- const remarkChart = (options = {}) => {
2207
- const { defaultWidth = 400, defaultHeight = 300 } = options;
2208
- return (tree) => {
2209
- visit(tree, "code", (node) => {
2210
- if (node.lang !== "chart") {
2211
- return;
2212
- }
2213
- try {
2214
- const config = JSON.parse(node.value);
2215
- if (!config.type || !config.data) {
2216
- console.warn(
2217
- "remarkChart: Invalid chart config - missing type or data"
2218
- );
2219
- return;
2220
- }
2221
- const chartConfig = {
2222
- ...config,
2223
- width: config.width ?? defaultWidth,
2224
- height: config.height ?? defaultHeight
2225
- };
2226
- node.value = JSON.stringify(chartConfig);
2227
- } catch (error) {
2228
- console.warn("remarkChart: Failed to parse chart config:", error);
2229
- }
2230
- });
2105
+ const remarkComponent = (_options = {}) => {
2106
+ return () => {
2231
2107
  };
2232
2108
  };
2233
2109
  function remarkRedact(matchers) {
@@ -2284,8 +2160,8 @@ const commonRedactMatchers = [
2284
2160
  bitcoinMatcher
2285
2161
  ];
2286
2162
  const SvgFile = (props) => /* @__PURE__ */ React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: 16, height: 16, viewBox: "0 0 16 16", fill: "currentColor", ...props }, /* @__PURE__ */ React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M2.7036 1.37034C3.04741 1.02653 3.51373 0.833374 3.99996 0.833374H9.33329H9.33331C9.47275 0.833374 9.59885 0.890449 9.68954 0.98251L13.6843 4.97722C13.7763 5.0679 13.8333 5.19398 13.8333 5.33337L13.8333 5.3379V13.3334C13.8333 13.8196 13.6401 14.2859 13.2963 14.6297C12.9525 14.9736 12.4862 15.1667 12 15.1667H3.99996C3.51373 15.1667 3.04741 14.9736 2.7036 14.6297C2.35978 14.2859 2.16663 13.8196 2.16663 13.3334V2.66671C2.16663 2.18048 2.35978 1.71416 2.7036 1.37034ZM3.99996 1.83337H8.83331V5.33337C8.83331 5.60952 9.05717 5.83337 9.33331 5.83337H12.8333V13.3334C12.8333 13.5544 12.7455 13.7663 12.5892 13.9226C12.4329 14.0789 12.221 14.1667 12 14.1667H3.99996C3.77895 14.1667 3.56698 14.0789 3.4107 13.9226C3.25442 13.7663 3.16663 13.5544 3.16663 13.3334V2.66671C3.16663 2.44569 3.25442 2.23373 3.4107 2.07745C3.56698 1.92117 3.77895 1.83337 3.99996 1.83337ZM9.83331 2.5405L12.1262 4.83337H9.83331V2.5405ZM5.33331 8.16663C5.05717 8.16663 4.83331 8.39048 4.83331 8.66663C4.83331 8.94277 5.05717 9.16663 5.33331 9.16663H10.6666C10.9428 9.16663 11.1666 8.94277 11.1666 8.66663C11.1666 8.39048 10.9428 8.16663 10.6666 8.16663H5.33331ZM4.83331 11.3334C4.83331 11.0572 5.05717 10.8334 5.33331 10.8334H10.6666C10.9428 10.8334 11.1666 11.0572 11.1666 11.3334C11.1666 11.6095 10.9428 11.8334 10.6666 11.8334H5.33331C5.05717 11.8334 4.83331 11.6095 4.83331 11.3334ZM5.33331 5.5C5.05717 5.5 4.83331 5.72386 4.83331 6C4.83331 6.27614 5.05717 6.5 5.33331 6.5H6.66665C6.94279 6.5 7.16665 6.27614 7.16665 6C7.16665 5.72386 6.94279 5.5 6.66665 5.5H5.33331Z" }));
2287
- const DefaultFileRenderer = lazy(() => import("./DefaultFileRenderer-C2MsQ9wz.js"));
2288
- const CSVFileRenderer = lazy(() => import("./CSVFileRenderer-BOdL4Jte.js"));
2163
+ const DefaultFileRenderer = lazy(() => import("./DefaultFileRenderer-Day12qYs.js"));
2164
+ const CSVFileRenderer = lazy(() => import("./CSVFileRenderer-C2E4Xnkz.js"));
2289
2165
  const ImageFileRenderer = lazy(() => import("./ImageFileRenderer-C8tVW3I8.js"));
2290
2166
  const PDFFileRenderer = lazy(() => import("./PDFFileRenderer-DQdFS2l6.js"));
2291
2167
  const FILE_TYPE_RENDERER_MAP = {
@@ -2302,7 +2178,7 @@ const MessageFile = ({
2302
2178
  }) => {
2303
2179
  const { theme } = useContext(ChatContext);
2304
2180
  const FileRenderer = useMemo(() => {
2305
- const Renderer = Object.keys(FILE_TYPE_RENDERER_MAP).find((key) => type == null ? void 0 : type.startsWith(key)) ?? "default";
2181
+ const Renderer = Object.keys(FILE_TYPE_RENDERER_MAP).find((key) => type?.startsWith(key)) ?? "default";
2306
2182
  return FILE_TYPE_RENDERER_MAP[Renderer] || DefaultFileRenderer;
2307
2183
  }, [type]);
2308
2184
  return /* @__PURE__ */ jsx(
@@ -2326,8 +2202,7 @@ const MessageFiles = memo(({ files, children }) => {
2326
2202
  }
2327
2203
  return files.reduce(
2328
2204
  (acc, file) => {
2329
- var _a;
2330
- if ((_a = file.type) == null ? void 0 : _a.startsWith("image/")) {
2205
+ if (file.type?.startsWith("image/")) {
2331
2206
  acc.imageFiles.push(file);
2332
2207
  } else {
2333
2208
  acc.otherFiles.push(file);
@@ -2629,7 +2504,6 @@ const SessionMessages = ({
2629
2504
  showMoreText = "Show more",
2630
2505
  showScrollBottomButton = false
2631
2506
  }) => {
2632
- var _a, _b, _c, _d, _e, _f;
2633
2507
  const { activeSession, theme } = useContext(ChatContext);
2634
2508
  const contentRef = useRef(null);
2635
2509
  const messagesRef = useRef(null);
@@ -2670,7 +2544,7 @@ const SessionMessages = ({
2670
2544
  }
2671
2545
  };
2672
2546
  const reversedConvos = useMemo(
2673
- () => [...(activeSession == null ? void 0 : activeSession.conversations) ?? []].reverse(),
2547
+ () => [...activeSession?.conversations ?? []].reverse(),
2674
2548
  [activeSession]
2675
2549
  );
2676
2550
  const { data, hasMore, showNext } = useInfinityList({
@@ -2678,7 +2552,7 @@ const SessionMessages = ({
2678
2552
  size: limit
2679
2553
  });
2680
2554
  const reReversedConvo = useMemo(() => [...data].reverse(), [data]);
2681
- const convosToRender = limit ? reReversedConvo : activeSession == null ? void 0 : activeSession.conversations;
2555
+ const convosToRender = limit ? reReversedConvo : activeSession?.conversations;
2682
2556
  if (!activeSession) {
2683
2557
  return /* @__PURE__ */ jsx(SessionEmpty, { children: newSessionContent });
2684
2558
  }
@@ -2688,7 +2562,7 @@ const SessionMessages = ({
2688
2562
  {
2689
2563
  className: cn(theme.messages.content, "h-full"),
2690
2564
  ref: contentRef,
2691
- id: activeSession == null ? void 0 : activeSession.id,
2565
+ id: activeSession?.id,
2692
2566
  children: [
2693
2567
  hasMore && /* @__PURE__ */ jsx(
2694
2568
  Button,
@@ -2722,7 +2596,7 @@ const SessionMessages = ({
2722
2596
  conversation.id
2723
2597
  ))
2724
2598
  },
2725
- activeSession == null ? void 0 : activeSession.id
2599
+ activeSession?.id
2726
2600
  ) })
2727
2601
  ]
2728
2602
  }
@@ -2734,12 +2608,12 @@ const SessionMessages = ({
2734
2608
  animate: { y: 0, opacity: 1 },
2735
2609
  exit: { y: 100, opacity: 0 },
2736
2610
  transition: { duration: 0.3, ease: "easeOut" },
2737
- className: (_c = (_b = (_a = theme.messages) == null ? void 0 : _a.message) == null ? void 0 : _b.scrollToBottom) == null ? void 0 : _c.container,
2611
+ className: theme.messages?.message?.scrollToBottom?.container,
2738
2612
  children: /* @__PURE__ */ jsx(
2739
2613
  IconButton,
2740
2614
  {
2741
2615
  onClick: handleScrollToBottom,
2742
- className: (_f = (_e = (_d = theme.messages) == null ? void 0 : _d.message) == null ? void 0 : _e.scrollToBottom) == null ? void 0 : _f.button,
2616
+ className: theme.messages?.message?.scrollToBottom?.button,
2743
2617
  size: "sm",
2744
2618
  children: /* @__PURE__ */ jsx(SvgArrowDown, {})
2745
2619
  }
@@ -2795,6 +2669,7 @@ const Chat = ({
2795
2669
  onNewSession,
2796
2670
  remarkPlugins = defaultRemarkPlugins,
2797
2671
  markdownComponents,
2672
+ components: componentCatalog2,
2798
2673
  disabled,
2799
2674
  style,
2800
2675
  className
@@ -2809,20 +2684,20 @@ const Chat = ({
2809
2684
  const handleSelectSession = useCallback(
2810
2685
  (sessionId) => {
2811
2686
  setInternalActiveSessionID(sessionId);
2812
- onSelectSession == null ? void 0 : onSelectSession(sessionId);
2687
+ onSelectSession?.(sessionId);
2813
2688
  },
2814
2689
  [onSelectSession]
2815
2690
  );
2816
2691
  const handleDeleteSession = useCallback(
2817
2692
  (sessionId) => {
2818
2693
  setInternalActiveSessionID(void 0);
2819
- onDeleteSession == null ? void 0 : onDeleteSession(sessionId);
2694
+ onDeleteSession?.(sessionId);
2820
2695
  },
2821
2696
  [onDeleteSession]
2822
2697
  );
2823
2698
  const handleCreateNewSession = useCallback(() => {
2824
2699
  setInternalActiveSessionID(void 0);
2825
- onNewSession == null ? void 0 : onNewSession();
2700
+ onNewSession?.();
2826
2701
  }, [onNewSession]);
2827
2702
  useHotkeys([
2828
2703
  {
@@ -2839,12 +2714,23 @@ const Chat = ({
2839
2714
  () => sessions.find((session) => session.id === internalActiveSessionID),
2840
2715
  [sessions, internalActiveSessionID]
2841
2716
  );
2717
+ const mergedRemarkPlugins = useMemo(() => {
2718
+ if (!componentCatalog2) return remarkPlugins;
2719
+ return [...remarkPlugins, componentCatalog2.remarkPlugin];
2720
+ }, [remarkPlugins, componentCatalog2]);
2721
+ const mergedMarkdownComponents = useMemo(() => {
2722
+ if (!componentCatalog2) return markdownComponents;
2723
+ return {
2724
+ ...componentCatalog2.components,
2725
+ ...markdownComponents
2726
+ };
2727
+ }, [markdownComponents, componentCatalog2]);
2842
2728
  const contextValue = useMemo(
2843
2729
  () => ({
2844
2730
  sessions,
2845
2731
  activeSession,
2846
- remarkPlugins,
2847
- markdownComponents,
2732
+ remarkPlugins: mergedRemarkPlugins,
2733
+ markdownComponents: mergedMarkdownComponents,
2848
2734
  theme,
2849
2735
  disabled,
2850
2736
  isLoading,
@@ -2864,8 +2750,8 @@ const Chat = ({
2864
2750
  viewType,
2865
2751
  disabled,
2866
2752
  theme,
2867
- remarkPlugins,
2868
- markdownComponents,
2753
+ mergedRemarkPlugins,
2754
+ mergedMarkdownComponents,
2869
2755
  sessions,
2870
2756
  activeSession,
2871
2757
  internalActiveSessionID,
@@ -2904,7 +2790,7 @@ const SessionListItem = memo(
2904
2790
  const { activeSessionId, selectSession, deleteSession, theme } = useContext(ChatContext);
2905
2791
  const Comp = children ? Slot : ListItem;
2906
2792
  const handleSelect = useCallback(() => {
2907
- selectSession == null ? void 0 : selectSession(session.id);
2793
+ selectSession?.(session.id);
2908
2794
  }, [selectSession, session.id]);
2909
2795
  const handleDelete = useCallback(
2910
2796
  (e) => {
@@ -2966,7 +2852,7 @@ const SessionsList = ({
2966
2852
  }),
2967
2853
  children: [
2968
2854
  /* @__PURE__ */ jsx(List, { children }),
2969
- templates && !activeSessionId && /* @__PURE__ */ jsx("div", { className: "mt-4", children: templates.map((template) => /* @__PURE__ */ jsx("div", { onClick: () => createSession == null ? void 0 : createSession(), children: /* @__PURE__ */ jsx(
2855
+ templates && !activeSessionId && /* @__PURE__ */ jsx("div", { className: "mt-4", children: templates.map((template) => /* @__PURE__ */ jsx("div", { onClick: () => createSession?.(), children: /* @__PURE__ */ jsx(
2970
2856
  SessionListItem,
2971
2857
  {
2972
2858
  session: {
@@ -2995,7 +2881,7 @@ const NewSessionButton = ({
2995
2881
  fullWidth: true,
2996
2882
  disableMargins: true,
2997
2883
  color: "primary",
2998
- startAdornment: /* @__PURE__ */ jsx(SvgPlus, {}),
2884
+ start: /* @__PURE__ */ jsx(SvgPlus, {}),
2999
2885
  className: cn(theme.sessions.create),
3000
2886
  disabled,
3001
2887
  onClick: createSession,
@@ -3131,7 +3017,7 @@ const ChatSuggestion = ({
3131
3017
  const { theme, disabled, isLoading } = useContext(ChatContext);
3132
3018
  const handleClick = () => {
3133
3019
  if (disabled || isLoading) return;
3134
- onClick == null ? void 0 : onClick(content);
3020
+ onClick?.(content);
3135
3021
  };
3136
3022
  return /* @__PURE__ */ jsx(
3137
3023
  Button,
@@ -3384,8 +3270,7 @@ function parseSSELine(line) {
3384
3270
  return null;
3385
3271
  }
3386
3272
  async function* parseSSE(response, signal) {
3387
- var _a;
3388
- const reader = (_a = response.body) == null ? void 0 : _a.getReader();
3273
+ const reader = response.body?.getReader();
3389
3274
  if (!reader) {
3390
3275
  throw new Error("Response body is not readable");
3391
3276
  }
@@ -3437,8 +3322,7 @@ function useAgUi({
3437
3322
  onEventRef.current = onEvent;
3438
3323
  useEffect(() => {
3439
3324
  return () => {
3440
- var _a;
3441
- (_a = abortRef.current) == null ? void 0 : _a.abort();
3325
+ abortRef.current?.abort();
3442
3326
  };
3443
3327
  }, []);
3444
3328
  const selectSession = useCallback((sessionId) => {
@@ -3466,15 +3350,13 @@ function useAgUi({
3466
3350
  setActiveSessionId(id);
3467
3351
  }, []);
3468
3352
  const stopMessage = useCallback(() => {
3469
- var _a;
3470
- (_a = abortRef.current) == null ? void 0 : _a.abort();
3353
+ abortRef.current?.abort();
3471
3354
  abortRef.current = null;
3472
3355
  setIsLoading(false);
3473
3356
  }, []);
3474
3357
  const sendMessage = useCallback(
3475
3358
  async (message) => {
3476
- var _a, _b, _c, _d, _e, _f;
3477
- (_a = abortRef.current) == null ? void 0 : _a.abort();
3359
+ abortRef.current?.abort();
3478
3360
  const abortController = new AbortController();
3479
3361
  abortRef.current = abortController;
3480
3362
  let sessionId = activeSessionId;
@@ -3501,7 +3383,7 @@ function useAgUi({
3501
3383
  );
3502
3384
  setIsLoading(true);
3503
3385
  const currentSession = [
3504
- ...((_b = sessions.find((s) => s.id === sessionId)) == null ? void 0 : _b.conversations) ?? []
3386
+ ...sessions.find((s) => s.id === sessionId)?.conversations ?? []
3505
3387
  ];
3506
3388
  const historyMessages = sessionsToAgUiMessages({
3507
3389
  conversations: currentSession
@@ -3549,11 +3431,11 @@ function useAgUi({
3549
3431
  abortController.signal
3550
3432
  )) {
3551
3433
  if (eventOrError instanceof Error) {
3552
- (_c = onErrorRef.current) == null ? void 0 : _c.call(onErrorRef, eventOrError);
3434
+ onErrorRef.current?.(eventOrError);
3553
3435
  continue;
3554
3436
  }
3555
3437
  const event = eventOrError;
3556
- (_d = onEventRef.current) == null ? void 0 : _d.call(onEventRef, event);
3438
+ onEventRef.current?.(event);
3557
3439
  switch (event.type) {
3558
3440
  case AgUiEventType.TEXT_MESSAGE_CONTENT: {
3559
3441
  responseText += event.delta;
@@ -3598,7 +3480,7 @@ function useAgUi({
3598
3480
  }
3599
3481
  case AgUiEventType.RUN_ERROR: {
3600
3482
  const err = new Error(event.message);
3601
- (_e = onErrorRef.current) == null ? void 0 : _e.call(onErrorRef, err);
3483
+ onErrorRef.current?.(err);
3602
3484
  break;
3603
3485
  }
3604
3486
  case AgUiEventType.RUN_FINISHED: {
@@ -3611,7 +3493,7 @@ function useAgUi({
3611
3493
  return;
3612
3494
  }
3613
3495
  const error = err instanceof Error ? err : new Error(String(err));
3614
- (_f = onErrorRef.current) == null ? void 0 : _f.call(onErrorRef, error);
3496
+ onErrorRef.current?.(error);
3615
3497
  } finally {
3616
3498
  if (abortRef.current === abortController) {
3617
3499
  abortRef.current = null;
@@ -3632,11 +3514,423 @@ function useAgUi({
3632
3514
  stopMessage
3633
3515
  };
3634
3516
  }
3517
+ function validateSpec(raw, definitions) {
3518
+ let parsed;
3519
+ try {
3520
+ parsed = JSON.parse(raw);
3521
+ } catch {
3522
+ return {
3523
+ ok: false,
3524
+ error: {
3525
+ type: "invalid_json",
3526
+ message: "Failed to parse component JSON",
3527
+ raw
3528
+ }
3529
+ };
3530
+ }
3531
+ const specArray = Array.isArray(parsed) ? parsed : [parsed];
3532
+ const validated = [];
3533
+ for (const item of specArray) {
3534
+ const result = validateSingleSpec(item, raw, definitions);
3535
+ if (!result.ok) {
3536
+ return { ok: false, error: result.error };
3537
+ }
3538
+ validated.push(result.spec);
3539
+ }
3540
+ return { ok: true, specs: validated };
3541
+ }
3542
+ function validateSingleSpec(item, raw, definitions) {
3543
+ if (!item || typeof item !== "object" || !("type" in item)) {
3544
+ return {
3545
+ ok: false,
3546
+ error: {
3547
+ type: "invalid_json",
3548
+ message: 'Component spec must be an object with a "type" field',
3549
+ raw
3550
+ }
3551
+ };
3552
+ }
3553
+ const spec = item;
3554
+ if (typeof spec.type !== "string") {
3555
+ return {
3556
+ ok: false,
3557
+ error: {
3558
+ type: "invalid_json",
3559
+ message: '"type" must be a string',
3560
+ raw
3561
+ }
3562
+ };
3563
+ }
3564
+ const componentType = spec.type;
3565
+ const definition = definitions[componentType];
3566
+ if (!definition) {
3567
+ return {
3568
+ ok: false,
3569
+ error: {
3570
+ type: "unknown_component",
3571
+ message: `Unknown component "${componentType}". Available: ${Object.keys(definitions).join(", ")}`,
3572
+ raw,
3573
+ componentType
3574
+ }
3575
+ };
3576
+ }
3577
+ const props = spec.props && typeof spec.props === "object" && !Array.isArray(spec.props) ? spec.props : {};
3578
+ const parseResult = definition.props.safeParse(props);
3579
+ if (!parseResult.success) {
3580
+ return {
3581
+ ok: false,
3582
+ error: {
3583
+ type: "invalid_props",
3584
+ message: `Invalid props for "${componentType}": ${parseResult.error.issues.map((i) => i.message).join(", ")}`,
3585
+ raw,
3586
+ componentType,
3587
+ issues: parseResult.error.issues.map((i) => ({
3588
+ message: i.message,
3589
+ path: i.path
3590
+ }))
3591
+ }
3592
+ };
3593
+ }
3594
+ let validatedChildren;
3595
+ if (spec.children) {
3596
+ if (!Array.isArray(spec.children)) {
3597
+ return {
3598
+ ok: false,
3599
+ error: {
3600
+ type: "invalid_json",
3601
+ message: '"children" must be an array',
3602
+ raw,
3603
+ componentType
3604
+ }
3605
+ };
3606
+ }
3607
+ validatedChildren = [];
3608
+ for (const child of spec.children) {
3609
+ const childResult = validateSingleSpec(child, raw, definitions);
3610
+ if (!childResult.ok) {
3611
+ return childResult;
3612
+ }
3613
+ validatedChildren.push(childResult.spec);
3614
+ }
3615
+ }
3616
+ return {
3617
+ ok: true,
3618
+ spec: {
3619
+ type: componentType,
3620
+ props: parseResult.data,
3621
+ ...validatedChildren ? { children: validatedChildren } : {}
3622
+ }
3623
+ };
3624
+ }
3625
+ const ComponentRenderer = ({
3626
+ raw,
3627
+ definitions,
3628
+ options
3629
+ }) => {
3630
+ const { theme, sendMessage } = useContext(ChatContext);
3631
+ const result = useMemo(
3632
+ () => validateSpec(raw, definitions),
3633
+ [raw, definitions]
3634
+ );
3635
+ if (!result.ok) {
3636
+ const error = result.error;
3637
+ const custom = options?.onError?.(error);
3638
+ if (custom !== void 0) {
3639
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3640
+ }
3641
+ return /* @__PURE__ */ jsx(
3642
+ ComponentError,
3643
+ {
3644
+ title: errorTitle(error.type),
3645
+ message: error.message,
3646
+ code: error.raw
3647
+ }
3648
+ );
3649
+ }
3650
+ const specs = result.specs;
3651
+ return /* @__PURE__ */ jsx("div", { className: theme.component?.base, children: specs.map((spec, index) => /* @__PURE__ */ jsx(
3652
+ SpecRenderer,
3653
+ {
3654
+ spec,
3655
+ definitions,
3656
+ options,
3657
+ sendMessage
3658
+ },
3659
+ `${spec.type}-${index}-${stableKey(spec)}`
3660
+ )) });
3661
+ };
3662
+ const SpecRenderer = ({
3663
+ spec,
3664
+ definitions,
3665
+ options,
3666
+ sendMessage
3667
+ }) => {
3668
+ const definition = definitions[spec.type];
3669
+ if (!definition) {
3670
+ const error = {
3671
+ type: "unknown_component",
3672
+ message: `Unknown component "${spec.type}"`,
3673
+ raw: JSON.stringify(spec),
3674
+ componentType: spec.type
3675
+ };
3676
+ const custom = options?.onError?.(error);
3677
+ if (custom !== void 0) {
3678
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3679
+ }
3680
+ return /* @__PURE__ */ jsx(ComponentError, { title: errorTitle(error.type), message: error.message });
3681
+ }
3682
+ const RenderedComponent = definition.component;
3683
+ const children = spec.children?.map((child, index) => /* @__PURE__ */ jsx(
3684
+ SpecRenderer,
3685
+ {
3686
+ spec: child,
3687
+ definitions,
3688
+ options,
3689
+ sendMessage
3690
+ },
3691
+ `${child.type}-${index}-${stableKey(child)}`
3692
+ ));
3693
+ return /* @__PURE__ */ jsx(SpecErrorBoundary, { spec, options, children: /* @__PURE__ */ jsx(RenderedComponent, { ...spec.props, sendMessage, children }) });
3694
+ };
3695
+ class SpecErrorBoundary extends Component {
3696
+ constructor() {
3697
+ super(...arguments);
3698
+ this.state = { error: null };
3699
+ }
3700
+ static getDerivedStateFromError(error) {
3701
+ return { error };
3702
+ }
3703
+ render() {
3704
+ if (this.state.error) {
3705
+ const { spec, options } = this.props;
3706
+ const catalogError = {
3707
+ type: "render_error",
3708
+ message: `Error rendering "${spec.type}": ${this.state.error.message}`,
3709
+ raw: JSON.stringify(spec),
3710
+ componentType: spec.type
3711
+ };
3712
+ const custom = options?.onError?.(catalogError);
3713
+ if (custom !== void 0) {
3714
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3715
+ }
3716
+ return /* @__PURE__ */ jsx(
3717
+ ComponentError,
3718
+ {
3719
+ title: errorTitle(catalogError.type),
3720
+ message: catalogError.message
3721
+ }
3722
+ );
3723
+ }
3724
+ return this.props.children;
3725
+ }
3726
+ }
3727
+ function stableKey(spec) {
3728
+ const str = JSON.stringify({
3729
+ t: spec.type,
3730
+ p: spec.props,
3731
+ c: spec.children
3732
+ });
3733
+ let h = 0;
3734
+ for (let i = 0; i < str.length; i++) {
3735
+ h = h * 31 + str.charCodeAt(i) | 0;
3736
+ }
3737
+ return (h >>> 0).toString(36);
3738
+ }
3739
+ function errorTitle(type) {
3740
+ switch (type) {
3741
+ case "unknown_component":
3742
+ return "Unknown Component";
3743
+ case "invalid_props":
3744
+ return "Invalid Props";
3745
+ case "render_error":
3746
+ return "Render Error";
3747
+ default:
3748
+ return "Invalid Component";
3749
+ }
3750
+ }
3751
+ function getChildText(children) {
3752
+ if (children === null || children === void 0) {
3753
+ return "";
3754
+ }
3755
+ if (typeof children === "string") {
3756
+ return children;
3757
+ }
3758
+ if (typeof children === "number") {
3759
+ return String(children);
3760
+ }
3761
+ if (Array.isArray(children)) {
3762
+ return children.map(getChildText).join("");
3763
+ }
3764
+ if (typeof children === "object") {
3765
+ if ("props" in children && children.props) {
3766
+ const element = children;
3767
+ return getChildText(element.props.children);
3768
+ }
3769
+ }
3770
+ return "";
3771
+ }
3772
+ function createComponentPre(definitions, options) {
3773
+ const language = options?.language ?? "component";
3774
+ const className = `language-${language}`;
3775
+ const ComponentPre = ({ children, ...props }) => {
3776
+ if (children && typeof children === "object" && "props" in children) {
3777
+ const codeElement = children;
3778
+ if (codeElement.props?.className === className) {
3779
+ const codeContent = getChildText(codeElement.props?.children);
3780
+ if (codeContent) {
3781
+ return /* @__PURE__ */ jsx(
3782
+ ComponentRenderer,
3783
+ {
3784
+ raw: codeContent,
3785
+ definitions,
3786
+ options
3787
+ }
3788
+ );
3789
+ }
3790
+ }
3791
+ }
3792
+ return /* @__PURE__ */ jsx("pre", { ...props, children });
3793
+ };
3794
+ ComponentPre.displayName = "ComponentPre";
3795
+ return ComponentPre;
3796
+ }
3797
+ function describeJsonSchemaProperty(prop, indent = "") {
3798
+ const description = prop.description ? ` // ${prop.description}` : "";
3799
+ if (prop.anyOf) {
3800
+ const nonNull = prop.anyOf.filter((s) => !(s.type === "null"));
3801
+ const hasNull = prop.anyOf.some((s) => s.type === "null");
3802
+ if (nonNull.length === 1 && hasNull) {
3803
+ return `${describeJsonSchemaProperty(nonNull[0], indent)} | null${description}`;
3804
+ }
3805
+ const parts = prop.anyOf.map(
3806
+ (s) => describeJsonSchemaProperty(s, indent)
3807
+ );
3808
+ return `${parts.join(" | ")}${description}`;
3809
+ }
3810
+ if (prop.enum) {
3811
+ return `${prop.enum.map((v) => `"${v}"`).join(" | ")}${description}`;
3812
+ }
3813
+ if (prop.type === "array") {
3814
+ const items = prop.items ? describeJsonSchemaProperty(prop.items, indent) : "any";
3815
+ return `${items}[]${description}`;
3816
+ }
3817
+ if (prop.type === "object" && prop.properties) {
3818
+ const required = new Set(prop.required ?? []);
3819
+ const fields = [];
3820
+ for (const [key, value] of Object.entries(prop.properties)) {
3821
+ const opt = required.has(key) ? "" : "?";
3822
+ fields.push(
3823
+ `${indent} ${key}: ${describeJsonSchemaProperty(value, indent + " ")}${opt}`
3824
+ );
3825
+ }
3826
+ return `{
3827
+ ${fields.join(",\n")}
3828
+ ${indent}}${description}`;
3829
+ }
3830
+ if (prop.type === "string") return `string${description}`;
3831
+ if (prop.type === "number" || prop.type === "integer")
3832
+ return `number${description}`;
3833
+ if (prop.type === "boolean") return `boolean${description}`;
3834
+ if (prop.type === "null") return `null${description}`;
3835
+ return `any${description}`;
3836
+ }
3837
+ function describeProps(schema) {
3838
+ try {
3839
+ const jsonSchema = z.toJSONSchema(schema);
3840
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
3841
+ return describeJsonSchemaProperty(jsonSchema);
3842
+ }
3843
+ return "Record<string, any>";
3844
+ } catch {
3845
+ return "Record<string, any>";
3846
+ }
3847
+ }
3848
+ function generatePrompt(definitions, language = "component") {
3849
+ const names = Object.keys(definitions);
3850
+ if (names.length === 0) {
3851
+ return "";
3852
+ }
3853
+ const componentDocs = names.map((name) => {
3854
+ const def = definitions[name];
3855
+ const propsDesc = describeProps(def.props);
3856
+ return `- **${name}**: ${def.description}
3857
+ Props: ${propsDesc}`;
3858
+ }).join("\n\n");
3859
+ return `When you need to render a dynamic UI component in your response, use a fenced code block with language \`${language}\` containing a JSON object:
3860
+
3861
+ \`\`\`${language}
3862
+ { "type": "ComponentName", "props": { ... } }
3863
+ \`\`\`
3864
+
3865
+ For multiple components, use a JSON array:
3866
+
3867
+ \`\`\`${language}
3868
+ [
3869
+ { "type": "ComponentA", "props": { ... } },
3870
+ { "type": "ComponentB", "props": { ... } }
3871
+ ]
3872
+ \`\`\`
3873
+
3874
+ For nested/composed layouts, use the "children" field:
3875
+
3876
+ \`\`\`${language}
3877
+ {
3878
+ "type": "Parent",
3879
+ "props": { ... },
3880
+ "children": [
3881
+ { "type": "Child", "props": { ... } }
3882
+ ]
3883
+ }
3884
+ \`\`\`
3885
+
3886
+ Available components:
3887
+
3888
+ ${componentDocs}`;
3889
+ }
3890
+ function componentCatalog(definitions, options) {
3891
+ const language = options?.language ?? "component";
3892
+ const plugin = remarkComponent.bind(void 0, {
3893
+ language
3894
+ });
3895
+ const Pre = createComponentPre(definitions, options);
3896
+ return {
3897
+ remarkPlugin: plugin,
3898
+ components: { pre: Pre },
3899
+ systemPrompt: () => generatePrompt(definitions, language),
3900
+ definitions
3901
+ };
3902
+ }
3903
+ function createChartComponentDef() {
3904
+ const chartPropsSchema = z.object({
3905
+ type: z.enum([
3906
+ "bar",
3907
+ "line",
3908
+ "area",
3909
+ "pie",
3910
+ "radialBar",
3911
+ "radialArea",
3912
+ "sparkline"
3913
+ ]).describe("Chart type"),
3914
+ data: z.array(z.object({ key: z.string(), data: z.number() })).describe("Array of { key, data } data points"),
3915
+ width: z.number().describe("Chart width in px").optional(),
3916
+ height: z.number().describe("Chart height in px").optional(),
3917
+ title: z.string().describe("Chart title").optional()
3918
+ });
3919
+ return {
3920
+ description: "Renders a chart. Supported types: bar, line, area, pie, radialBar, radialArea, sparkline",
3921
+ props: chartPropsSchema,
3922
+ component: ({
3923
+ children: _children,
3924
+ sendMessage: _sendMessage,
3925
+ ...config
3926
+ }) => /* @__PURE__ */ jsx(ChartRenderer, { config })
3927
+ };
3928
+ }
3635
3929
  export {
3636
3930
  remarkRedact as $,
3637
3931
  AgUiEventType as A,
3638
3932
  SessionMessages as B,
3639
- ChartError as C,
3933
+ ChartRenderer as C,
3640
3934
  SessionMessagesHeader as D,
3641
3935
  SessionsGroup as E,
3642
3936
  FileInput as F,
@@ -3645,36 +3939,36 @@ export {
3645
3939
  TableDataCell as I,
3646
3940
  TableHeaderCell as J,
3647
3941
  bitcoinMatcher as K,
3648
- chartComponents as L,
3942
+ chatTheme as L,
3649
3943
  Markdown as M,
3650
3944
  NewSessionButton as N,
3651
- chatTheme as O,
3652
- commonRedactMatchers as P,
3653
- creditCardMatcher as Q,
3945
+ commonRedactMatchers as O,
3946
+ componentCatalog as P,
3947
+ createChartComponentDef as Q,
3654
3948
  RichTextInput as R,
3655
3949
  SvgFile as S,
3656
3950
  TableComponent as T,
3657
- dark as U,
3658
- getChildText as V,
3659
- isChartClassName as W,
3660
- light as X,
3661
- parseChartConfig as Y,
3662
- remarkChart as Z,
3951
+ createComponentPre as U,
3952
+ creditCardMatcher as V,
3953
+ dark as W,
3954
+ generatePrompt as X,
3955
+ light as Y,
3956
+ remarkComponent as Z,
3663
3957
  remarkCve as _,
3664
3958
  SvgCopy as a,
3665
3959
  ssnMatcher as a0,
3666
3960
  useAgUi as a1,
3667
- validateChartData as a2,
3961
+ validateSpec as a2,
3668
3962
  AppBar as b,
3669
- ChartPre as c,
3670
- ChartRenderer as d,
3671
- Chat as e,
3672
- ChatBubble as f,
3673
- ChatContext as g,
3674
- ChatInput as h,
3675
- ChatSuggestion as i,
3676
- ChatSuggestions as j,
3677
- CodeHighlighter as k,
3963
+ Chat as c,
3964
+ ChatBubble as d,
3965
+ ChatContext as e,
3966
+ ChatInput as f,
3967
+ ChatSuggestion as g,
3968
+ ChatSuggestions as h,
3969
+ CodeHighlighter as i,
3970
+ ComponentError as j,
3971
+ ComponentRenderer as k,
3678
3972
  MentionList as l,
3679
3973
  MessageActions as m,
3680
3974
  MessageFile as n,
@@ -3691,4 +3985,4 @@ export {
3691
3985
  SessionMessage as y,
3692
3986
  SessionMessagePanel as z
3693
3987
  };
3694
- //# sourceMappingURL=index-DdRyk11n.js.map
3988
+ //# sourceMappingURL=index-CZSBRZbI.js.map