reachat 2.2.0 → 3.0.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 (44) hide show
  1. package/dist/{CSVFileRenderer-BOdL4Jte.js → CSVFileRenderer-C2tuexJf.js} +2 -2
  2. package/dist/{CSVFileRenderer-BOdL4Jte.js.map → CSVFileRenderer-C2tuexJf.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-CJ3jwiQa.js} +2 -2
  17. package/dist/{DefaultFileRenderer-C2MsQ9wz.js.map → DefaultFileRenderer-CJ3jwiQa.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 +259 -77
  25. package/dist/{index-DdRyk11n.js → index-8tlsyFe-.js} +470 -147
  26. package/dist/index-8tlsyFe-.js.map +1 -0
  27. package/dist/index.css +26 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +22 -22
  30. package/dist/index.umd.cjs +454 -131
  31. package/dist/index.umd.cjs.map +1 -1
  32. package/dist/stories/Charts.stories.tsx +118 -130
  33. package/dist/stories/ComponentCatalog.stories.tsx +509 -0
  34. package/dist/stories/{ChartError.stories.tsx → ComponentError.stories.tsx} +14 -11
  35. package/dist/theme.d.ts +3 -0
  36. package/dist/utils/getChildText.d.ts +10 -0
  37. package/dist/utils/getChildText.spec.d.ts +1 -0
  38. package/package.json +4 -6
  39. package/dist/Markdown/charts/ChartPre.d.ts +0 -6
  40. package/dist/Markdown/charts/chartHelpers.d.ts +0 -40
  41. package/dist/Markdown/plugins/remarkChart.d.ts +0 -59
  42. package/dist/index-DdRyk11n.js.map +0 -1
  43. package/dist/stories/Integration.stories.tsx +0 -312
  44. /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({
@@ -315,6 +315,9 @@ const chatTheme = {
315
315
  ].join(" "),
316
316
  title: "text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-2"
317
317
  }
318
+ },
319
+ component: {
320
+ base: "my-4"
318
321
  }
319
322
  };
320
323
  const POPUP_STYLE = { zIndex: 9999 };
@@ -1958,6 +1961,8 @@ const Markdown = ({
1958
1961
  li: (props) => /* @__PURE__ */ jsx("li", { ...props, className: cn(theme.messages.message.markdown.li) }),
1959
1962
  ul: (props) => /* @__PURE__ */ jsx("ul", { ...props, className: cn(theme.messages.message.markdown.ul) }),
1960
1963
  ol: (props) => /* @__PURE__ */ jsx("ol", { ...props, className: cn(theme.messages.message.markdown.ol) }),
1964
+ // 'redact' is a custom element created by remarkRedact, not a standard
1965
+ // HTML tag, so it falls outside react-markdown's Components type.
1961
1966
  redact: (props) => /* @__PURE__ */ jsx(
1962
1967
  Redact,
1963
1968
  {
@@ -1983,7 +1988,7 @@ const Markdown = ({
1983
1988
  }
1984
1989
  );
1985
1990
  };
1986
- const ChartError = ({
1991
+ const ComponentError = ({
1987
1992
  variant = "error",
1988
1993
  title,
1989
1994
  message,
@@ -2011,12 +2016,12 @@ const ChartRenderer = ({
2011
2016
  data: d.data
2012
2017
  }));
2013
2018
  if (!chartData || chartData.length === 0) {
2014
- return /* @__PURE__ */ jsx(ChartError, { variant: "warning", message: "No chart data available" });
2019
+ return /* @__PURE__ */ jsx(ComponentError, { variant: "warning", message: "No chart data available" });
2015
2020
  }
2016
2021
  for (const point of chartData) {
2017
2022
  if (typeof point.data !== "number" || isNaN(point.data)) {
2018
2023
  return /* @__PURE__ */ jsx(
2019
- ChartError,
2024
+ ComponentError,
2020
2025
  {
2021
2026
  message: `Invalid data point: ${JSON.stringify(point)}`
2022
2027
  }
@@ -2085,10 +2090,10 @@ const ChartRenderer = ({
2085
2090
  case "sparkline":
2086
2091
  return /* @__PURE__ */ jsx(SparklineChart, { width, height, data: chartData });
2087
2092
  default:
2088
- return /* @__PURE__ */ jsx(ChartError, { message: `Unknown chart type: ${type}` });
2093
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Unknown chart type: ${type}` });
2089
2094
  }
2090
2095
  } catch (error) {
2091
- return /* @__PURE__ */ jsx(ChartError, { message: `Chart render error: ${String(error)}` });
2096
+ return /* @__PURE__ */ jsx(ComponentError, { message: `Chart render error: ${String(error)}` });
2092
2097
  }
2093
2098
  }, [type, data, width, height]);
2094
2099
  return /* @__PURE__ */ jsxs("div", { className: cn(theme.chart.base, className), children: [
@@ -2096,93 +2101,6 @@ const ChartRenderer = ({
2096
2101
  /* @__PURE__ */ jsx("div", { className: theme.chart.content, children: chartElement })
2097
2102
  ] });
2098
2103
  };
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
2104
  const CVE_REGEX = /(CVE-(19|20)\d{2}-\d{4,7})/gi;
2187
2105
  function remarkCve() {
2188
2106
  return (tree, _file) => {
@@ -2203,31 +2121,8 @@ function remarkCve() {
2203
2121
  ];
2204
2122
  }
2205
2123
  }
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
- });
2124
+ const remarkComponent = (_options = {}) => {
2125
+ return () => {
2231
2126
  };
2232
2127
  };
2233
2128
  function remarkRedact(matchers) {
@@ -2284,8 +2179,8 @@ const commonRedactMatchers = [
2284
2179
  bitcoinMatcher
2285
2180
  ];
2286
2181
  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"));
2182
+ const DefaultFileRenderer = lazy(() => import("./DefaultFileRenderer-CJ3jwiQa.js"));
2183
+ const CSVFileRenderer = lazy(() => import("./CSVFileRenderer-C2tuexJf.js"));
2289
2184
  const ImageFileRenderer = lazy(() => import("./ImageFileRenderer-C8tVW3I8.js"));
2290
2185
  const PDFFileRenderer = lazy(() => import("./PDFFileRenderer-DQdFS2l6.js"));
2291
2186
  const FILE_TYPE_RENDERER_MAP = {
@@ -2795,6 +2690,7 @@ const Chat = ({
2795
2690
  onNewSession,
2796
2691
  remarkPlugins = defaultRemarkPlugins,
2797
2692
  markdownComponents,
2693
+ components: componentCatalog2,
2798
2694
  disabled,
2799
2695
  style,
2800
2696
  className
@@ -2839,12 +2735,23 @@ const Chat = ({
2839
2735
  () => sessions.find((session) => session.id === internalActiveSessionID),
2840
2736
  [sessions, internalActiveSessionID]
2841
2737
  );
2738
+ const mergedRemarkPlugins = useMemo(() => {
2739
+ if (!componentCatalog2) return remarkPlugins;
2740
+ return [...remarkPlugins, componentCatalog2.remarkPlugin];
2741
+ }, [remarkPlugins, componentCatalog2]);
2742
+ const mergedMarkdownComponents = useMemo(() => {
2743
+ if (!componentCatalog2) return markdownComponents;
2744
+ return {
2745
+ ...componentCatalog2.components,
2746
+ ...markdownComponents
2747
+ };
2748
+ }, [markdownComponents, componentCatalog2]);
2842
2749
  const contextValue = useMemo(
2843
2750
  () => ({
2844
2751
  sessions,
2845
2752
  activeSession,
2846
- remarkPlugins,
2847
- markdownComponents,
2753
+ remarkPlugins: mergedRemarkPlugins,
2754
+ markdownComponents: mergedMarkdownComponents,
2848
2755
  theme,
2849
2756
  disabled,
2850
2757
  isLoading,
@@ -2864,8 +2771,8 @@ const Chat = ({
2864
2771
  viewType,
2865
2772
  disabled,
2866
2773
  theme,
2867
- remarkPlugins,
2868
- markdownComponents,
2774
+ mergedRemarkPlugins,
2775
+ mergedMarkdownComponents,
2869
2776
  sessions,
2870
2777
  activeSession,
2871
2778
  internalActiveSessionID,
@@ -3632,11 +3539,427 @@ function useAgUi({
3632
3539
  stopMessage
3633
3540
  };
3634
3541
  }
3542
+ function validateSpec(raw, definitions) {
3543
+ let parsed;
3544
+ try {
3545
+ parsed = JSON.parse(raw);
3546
+ } catch {
3547
+ return {
3548
+ ok: false,
3549
+ error: {
3550
+ type: "invalid_json",
3551
+ message: "Failed to parse component JSON",
3552
+ raw
3553
+ }
3554
+ };
3555
+ }
3556
+ const specArray = Array.isArray(parsed) ? parsed : [parsed];
3557
+ const validated = [];
3558
+ for (const item of specArray) {
3559
+ const result = validateSingleSpec(item, raw, definitions);
3560
+ if (!result.ok) {
3561
+ return { ok: false, error: result.error };
3562
+ }
3563
+ validated.push(result.spec);
3564
+ }
3565
+ return { ok: true, specs: validated };
3566
+ }
3567
+ function validateSingleSpec(item, raw, definitions) {
3568
+ if (!item || typeof item !== "object" || !("type" in item)) {
3569
+ return {
3570
+ ok: false,
3571
+ error: {
3572
+ type: "invalid_json",
3573
+ message: 'Component spec must be an object with a "type" field',
3574
+ raw
3575
+ }
3576
+ };
3577
+ }
3578
+ const spec = item;
3579
+ if (typeof spec.type !== "string") {
3580
+ return {
3581
+ ok: false,
3582
+ error: {
3583
+ type: "invalid_json",
3584
+ message: '"type" must be a string',
3585
+ raw
3586
+ }
3587
+ };
3588
+ }
3589
+ const componentType = spec.type;
3590
+ const definition = definitions[componentType];
3591
+ if (!definition) {
3592
+ return {
3593
+ ok: false,
3594
+ error: {
3595
+ type: "unknown_component",
3596
+ message: `Unknown component "${componentType}". Available: ${Object.keys(definitions).join(", ")}`,
3597
+ raw,
3598
+ componentType
3599
+ }
3600
+ };
3601
+ }
3602
+ const props = spec.props && typeof spec.props === "object" && !Array.isArray(spec.props) ? spec.props : {};
3603
+ const parseResult = definition.props.safeParse(props);
3604
+ if (!parseResult.success) {
3605
+ return {
3606
+ ok: false,
3607
+ error: {
3608
+ type: "invalid_props",
3609
+ message: `Invalid props for "${componentType}": ${parseResult.error.issues.map((i) => i.message).join(", ")}`,
3610
+ raw,
3611
+ componentType,
3612
+ issues: parseResult.error.issues.map((i) => ({
3613
+ message: i.message,
3614
+ path: i.path
3615
+ }))
3616
+ }
3617
+ };
3618
+ }
3619
+ let validatedChildren;
3620
+ if (spec.children) {
3621
+ if (!Array.isArray(spec.children)) {
3622
+ return {
3623
+ ok: false,
3624
+ error: {
3625
+ type: "invalid_json",
3626
+ message: '"children" must be an array',
3627
+ raw,
3628
+ componentType
3629
+ }
3630
+ };
3631
+ }
3632
+ validatedChildren = [];
3633
+ for (const child of spec.children) {
3634
+ const childResult = validateSingleSpec(child, raw, definitions);
3635
+ if (!childResult.ok) {
3636
+ return childResult;
3637
+ }
3638
+ validatedChildren.push(childResult.spec);
3639
+ }
3640
+ }
3641
+ return {
3642
+ ok: true,
3643
+ spec: {
3644
+ type: componentType,
3645
+ props: parseResult.data,
3646
+ ...validatedChildren ? { children: validatedChildren } : {}
3647
+ }
3648
+ };
3649
+ }
3650
+ const ComponentRenderer = ({
3651
+ raw,
3652
+ definitions,
3653
+ options
3654
+ }) => {
3655
+ var _a, _b;
3656
+ const { theme, sendMessage } = useContext(ChatContext);
3657
+ const result = useMemo(
3658
+ () => validateSpec(raw, definitions),
3659
+ [raw, definitions]
3660
+ );
3661
+ if (!result.ok) {
3662
+ const error = result.error;
3663
+ const custom = (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, error);
3664
+ if (custom !== void 0) {
3665
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3666
+ }
3667
+ return /* @__PURE__ */ jsx(
3668
+ ComponentError,
3669
+ {
3670
+ title: errorTitle(error.type),
3671
+ message: error.message,
3672
+ code: error.raw
3673
+ }
3674
+ );
3675
+ }
3676
+ const specs = result.specs;
3677
+ return /* @__PURE__ */ jsx("div", { className: (_b = theme.component) == null ? void 0 : _b.base, children: specs.map((spec, index) => /* @__PURE__ */ jsx(
3678
+ SpecRenderer,
3679
+ {
3680
+ spec,
3681
+ definitions,
3682
+ options,
3683
+ sendMessage
3684
+ },
3685
+ `${spec.type}-${index}-${stableKey(spec)}`
3686
+ )) });
3687
+ };
3688
+ const SpecRenderer = ({
3689
+ spec,
3690
+ definitions,
3691
+ options,
3692
+ sendMessage
3693
+ }) => {
3694
+ var _a, _b;
3695
+ const definition = definitions[spec.type];
3696
+ if (!definition) {
3697
+ const error = {
3698
+ type: "unknown_component",
3699
+ message: `Unknown component "${spec.type}"`,
3700
+ raw: JSON.stringify(spec),
3701
+ componentType: spec.type
3702
+ };
3703
+ const custom = (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, error);
3704
+ if (custom !== void 0) {
3705
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3706
+ }
3707
+ return /* @__PURE__ */ jsx(ComponentError, { title: errorTitle(error.type), message: error.message });
3708
+ }
3709
+ const RenderedComponent = definition.component;
3710
+ const children = (_b = spec.children) == null ? void 0 : _b.map((child, index) => /* @__PURE__ */ jsx(
3711
+ SpecRenderer,
3712
+ {
3713
+ spec: child,
3714
+ definitions,
3715
+ options,
3716
+ sendMessage
3717
+ },
3718
+ `${child.type}-${index}-${stableKey(child)}`
3719
+ ));
3720
+ return /* @__PURE__ */ jsx(SpecErrorBoundary, { spec, options, children: /* @__PURE__ */ jsx(RenderedComponent, { ...spec.props, sendMessage, children }) });
3721
+ };
3722
+ class SpecErrorBoundary extends Component {
3723
+ constructor() {
3724
+ super(...arguments);
3725
+ this.state = { error: null };
3726
+ }
3727
+ static getDerivedStateFromError(error) {
3728
+ return { error };
3729
+ }
3730
+ render() {
3731
+ var _a;
3732
+ if (this.state.error) {
3733
+ const { spec, options } = this.props;
3734
+ const catalogError = {
3735
+ type: "render_error",
3736
+ message: `Error rendering "${spec.type}": ${this.state.error.message}`,
3737
+ raw: JSON.stringify(spec),
3738
+ componentType: spec.type
3739
+ };
3740
+ const custom = (_a = options == null ? void 0 : options.onError) == null ? void 0 : _a.call(options, catalogError);
3741
+ if (custom !== void 0) {
3742
+ return /* @__PURE__ */ jsx(Fragment, { children: custom });
3743
+ }
3744
+ return /* @__PURE__ */ jsx(
3745
+ ComponentError,
3746
+ {
3747
+ title: errorTitle(catalogError.type),
3748
+ message: catalogError.message
3749
+ }
3750
+ );
3751
+ }
3752
+ return this.props.children;
3753
+ }
3754
+ }
3755
+ function stableKey(spec) {
3756
+ const str = JSON.stringify({
3757
+ t: spec.type,
3758
+ p: spec.props,
3759
+ c: spec.children
3760
+ });
3761
+ let h = 0;
3762
+ for (let i = 0; i < str.length; i++) {
3763
+ h = h * 31 + str.charCodeAt(i) | 0;
3764
+ }
3765
+ return (h >>> 0).toString(36);
3766
+ }
3767
+ function errorTitle(type) {
3768
+ switch (type) {
3769
+ case "unknown_component":
3770
+ return "Unknown Component";
3771
+ case "invalid_props":
3772
+ return "Invalid Props";
3773
+ case "render_error":
3774
+ return "Render Error";
3775
+ default:
3776
+ return "Invalid Component";
3777
+ }
3778
+ }
3779
+ function getChildText(children) {
3780
+ if (children === null || children === void 0) {
3781
+ return "";
3782
+ }
3783
+ if (typeof children === "string") {
3784
+ return children;
3785
+ }
3786
+ if (typeof children === "number") {
3787
+ return String(children);
3788
+ }
3789
+ if (Array.isArray(children)) {
3790
+ return children.map(getChildText).join("");
3791
+ }
3792
+ if (typeof children === "object") {
3793
+ if ("props" in children && children.props) {
3794
+ const element = children;
3795
+ return getChildText(element.props.children);
3796
+ }
3797
+ }
3798
+ return "";
3799
+ }
3800
+ function createComponentPre(definitions, options) {
3801
+ const language = (options == null ? void 0 : options.language) ?? "component";
3802
+ const className = `language-${language}`;
3803
+ const ComponentPre = ({ children, ...props }) => {
3804
+ var _a, _b;
3805
+ if (children && typeof children === "object" && "props" in children) {
3806
+ const codeElement = children;
3807
+ if (((_a = codeElement.props) == null ? void 0 : _a.className) === className) {
3808
+ const codeContent = getChildText((_b = codeElement.props) == null ? void 0 : _b.children);
3809
+ if (codeContent) {
3810
+ return /* @__PURE__ */ jsx(
3811
+ ComponentRenderer,
3812
+ {
3813
+ raw: codeContent,
3814
+ definitions,
3815
+ options
3816
+ }
3817
+ );
3818
+ }
3819
+ }
3820
+ }
3821
+ return /* @__PURE__ */ jsx("pre", { ...props, children });
3822
+ };
3823
+ ComponentPre.displayName = "ComponentPre";
3824
+ return ComponentPre;
3825
+ }
3826
+ function describeJsonSchemaProperty(prop, indent = "") {
3827
+ const description = prop.description ? ` // ${prop.description}` : "";
3828
+ if (prop.anyOf) {
3829
+ const nonNull = prop.anyOf.filter((s) => !(s.type === "null"));
3830
+ const hasNull = prop.anyOf.some((s) => s.type === "null");
3831
+ if (nonNull.length === 1 && hasNull) {
3832
+ return `${describeJsonSchemaProperty(nonNull[0], indent)} | null${description}`;
3833
+ }
3834
+ const parts = prop.anyOf.map(
3835
+ (s) => describeJsonSchemaProperty(s, indent)
3836
+ );
3837
+ return `${parts.join(" | ")}${description}`;
3838
+ }
3839
+ if (prop.enum) {
3840
+ return `${prop.enum.map((v) => `"${v}"`).join(" | ")}${description}`;
3841
+ }
3842
+ if (prop.type === "array") {
3843
+ const items = prop.items ? describeJsonSchemaProperty(prop.items, indent) : "any";
3844
+ return `${items}[]${description}`;
3845
+ }
3846
+ if (prop.type === "object" && prop.properties) {
3847
+ const required = new Set(prop.required ?? []);
3848
+ const fields = [];
3849
+ for (const [key, value] of Object.entries(prop.properties)) {
3850
+ const opt = required.has(key) ? "" : "?";
3851
+ fields.push(
3852
+ `${indent} ${key}: ${describeJsonSchemaProperty(value, indent + " ")}${opt}`
3853
+ );
3854
+ }
3855
+ return `{
3856
+ ${fields.join(",\n")}
3857
+ ${indent}}${description}`;
3858
+ }
3859
+ if (prop.type === "string") return `string${description}`;
3860
+ if (prop.type === "number" || prop.type === "integer")
3861
+ return `number${description}`;
3862
+ if (prop.type === "boolean") return `boolean${description}`;
3863
+ if (prop.type === "null") return `null${description}`;
3864
+ return `any${description}`;
3865
+ }
3866
+ function describeProps(schema) {
3867
+ try {
3868
+ const jsonSchema = z.toJSONSchema(schema);
3869
+ if (jsonSchema.type === "object" && jsonSchema.properties) {
3870
+ return describeJsonSchemaProperty(jsonSchema);
3871
+ }
3872
+ return "Record<string, any>";
3873
+ } catch {
3874
+ return "Record<string, any>";
3875
+ }
3876
+ }
3877
+ function generatePrompt(definitions, language = "component") {
3878
+ const names = Object.keys(definitions);
3879
+ if (names.length === 0) {
3880
+ return "";
3881
+ }
3882
+ const componentDocs = names.map((name) => {
3883
+ const def = definitions[name];
3884
+ const propsDesc = describeProps(def.props);
3885
+ return `- **${name}**: ${def.description}
3886
+ Props: ${propsDesc}`;
3887
+ }).join("\n\n");
3888
+ 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:
3889
+
3890
+ \`\`\`${language}
3891
+ { "type": "ComponentName", "props": { ... } }
3892
+ \`\`\`
3893
+
3894
+ For multiple components, use a JSON array:
3895
+
3896
+ \`\`\`${language}
3897
+ [
3898
+ { "type": "ComponentA", "props": { ... } },
3899
+ { "type": "ComponentB", "props": { ... } }
3900
+ ]
3901
+ \`\`\`
3902
+
3903
+ For nested/composed layouts, use the "children" field:
3904
+
3905
+ \`\`\`${language}
3906
+ {
3907
+ "type": "Parent",
3908
+ "props": { ... },
3909
+ "children": [
3910
+ { "type": "Child", "props": { ... } }
3911
+ ]
3912
+ }
3913
+ \`\`\`
3914
+
3915
+ Available components:
3916
+
3917
+ ${componentDocs}`;
3918
+ }
3919
+ function componentCatalog(definitions, options) {
3920
+ const language = (options == null ? void 0 : options.language) ?? "component";
3921
+ const plugin = remarkComponent.bind(void 0, {
3922
+ language
3923
+ });
3924
+ const Pre = createComponentPre(definitions, options);
3925
+ return {
3926
+ remarkPlugin: plugin,
3927
+ components: { pre: Pre },
3928
+ systemPrompt: () => generatePrompt(definitions, language),
3929
+ definitions
3930
+ };
3931
+ }
3932
+ function createChartComponentDef() {
3933
+ const chartPropsSchema = z.object({
3934
+ type: z.enum([
3935
+ "bar",
3936
+ "line",
3937
+ "area",
3938
+ "pie",
3939
+ "radialBar",
3940
+ "radialArea",
3941
+ "sparkline"
3942
+ ]).describe("Chart type"),
3943
+ data: z.array(z.object({ key: z.string(), data: z.number() })).describe("Array of { key, data } data points"),
3944
+ width: z.number().describe("Chart width in px").optional(),
3945
+ height: z.number().describe("Chart height in px").optional(),
3946
+ title: z.string().describe("Chart title").optional()
3947
+ });
3948
+ return {
3949
+ description: "Renders a chart. Supported types: bar, line, area, pie, radialBar, radialArea, sparkline",
3950
+ props: chartPropsSchema,
3951
+ component: ({
3952
+ children: _children,
3953
+ sendMessage: _sendMessage,
3954
+ ...config
3955
+ }) => /* @__PURE__ */ jsx(ChartRenderer, { config })
3956
+ };
3957
+ }
3635
3958
  export {
3636
3959
  remarkRedact as $,
3637
3960
  AgUiEventType as A,
3638
3961
  SessionMessages as B,
3639
- ChartError as C,
3962
+ ChartRenderer as C,
3640
3963
  SessionMessagesHeader as D,
3641
3964
  SessionsGroup as E,
3642
3965
  FileInput as F,
@@ -3645,36 +3968,36 @@ export {
3645
3968
  TableDataCell as I,
3646
3969
  TableHeaderCell as J,
3647
3970
  bitcoinMatcher as K,
3648
- chartComponents as L,
3971
+ chatTheme as L,
3649
3972
  Markdown as M,
3650
3973
  NewSessionButton as N,
3651
- chatTheme as O,
3652
- commonRedactMatchers as P,
3653
- creditCardMatcher as Q,
3974
+ commonRedactMatchers as O,
3975
+ componentCatalog as P,
3976
+ createChartComponentDef as Q,
3654
3977
  RichTextInput as R,
3655
3978
  SvgFile as S,
3656
3979
  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,
3980
+ createComponentPre as U,
3981
+ creditCardMatcher as V,
3982
+ dark as W,
3983
+ generatePrompt as X,
3984
+ light as Y,
3985
+ remarkComponent as Z,
3663
3986
  remarkCve as _,
3664
3987
  SvgCopy as a,
3665
3988
  ssnMatcher as a0,
3666
3989
  useAgUi as a1,
3667
- validateChartData as a2,
3990
+ validateSpec as a2,
3668
3991
  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,
3992
+ Chat as c,
3993
+ ChatBubble as d,
3994
+ ChatContext as e,
3995
+ ChatInput as f,
3996
+ ChatSuggestion as g,
3997
+ ChatSuggestions as h,
3998
+ CodeHighlighter as i,
3999
+ ComponentError as j,
4000
+ ComponentRenderer as k,
3678
4001
  MentionList as l,
3679
4002
  MessageActions as m,
3680
4003
  MessageFile as n,
@@ -3691,4 +4014,4 @@ export {
3691
4014
  SessionMessage as y,
3692
4015
  SessionMessagePanel as z
3693
4016
  };
3694
- //# sourceMappingURL=index-DdRyk11n.js.map
4017
+ //# sourceMappingURL=index-8tlsyFe-.js.map