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.
- package/dist/{CSVFileRenderer-BOdL4Jte.js → CSVFileRenderer-C2E4Xnkz.js} +2 -2
- package/dist/{CSVFileRenderer-BOdL4Jte.js.map → CSVFileRenderer-C2E4Xnkz.js.map} +1 -1
- package/dist/Chat.d.ts +12 -0
- package/dist/{Markdown/charts/ChartError.d.ts → ComponentCatalog/ComponentError.d.ts} +2 -2
- package/dist/ComponentCatalog/ComponentPre.d.ts +18 -0
- package/dist/ComponentCatalog/ComponentRenderer.d.ts +17 -0
- package/dist/ComponentCatalog/chartComponentDef.d.ts +36 -0
- package/dist/ComponentCatalog/componentCatalog.d.ts +44 -0
- package/dist/ComponentCatalog/componentCatalog.spec.d.ts +1 -0
- package/dist/ComponentCatalog/generatePrompt.d.ts +9 -0
- package/dist/ComponentCatalog/generatePrompt.spec.d.ts +1 -0
- package/dist/ComponentCatalog/index.d.ts +9 -0
- package/dist/ComponentCatalog/types.d.ts +108 -0
- package/dist/ComponentCatalog/validateSpec.d.ts +17 -0
- package/dist/ComponentCatalog/validateSpec.spec.d.ts +1 -0
- package/dist/{DefaultFileRenderer-C2MsQ9wz.js → DefaultFileRenderer-Day12qYs.js} +2 -2
- package/dist/{DefaultFileRenderer-C2MsQ9wz.js.map → DefaultFileRenderer-Day12qYs.js.map} +1 -1
- package/dist/Markdown/charts/ChartRenderer.d.ts +1 -1
- package/dist/Markdown/charts/ComponentError.d.ts +1 -0
- package/dist/Markdown/charts/index.d.ts +2 -6
- package/dist/Markdown/charts/types.d.ts +21 -0
- package/dist/Markdown/plugins/index.d.ts +1 -1
- package/dist/Markdown/plugins/remarkComponent.d.ts +27 -0
- package/dist/docs.json +275 -93
- package/dist/{index-DdRyk11n.js → index-CZSBRZbI.js} +524 -230
- package/dist/index-CZSBRZbI.js.map +1 -0
- package/dist/index.css +101 -1077
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -22
- package/dist/index.umd.cjs +509 -215
- package/dist/index.umd.cjs.map +1 -1
- package/dist/stories/Changelog.mdx +1 -1
- package/dist/stories/Charts.stories.tsx +118 -130
- package/dist/stories/ComponentCatalog.stories.tsx +509 -0
- package/dist/stories/{ChartError.stories.tsx → ComponentError.stories.tsx} +14 -11
- package/dist/stories/Intro.mdx +1 -1
- package/dist/theme.d.ts +3 -0
- package/dist/utils/getChildText.d.ts +10 -0
- package/dist/utils/getChildText.spec.d.ts +1 -0
- package/package.json +27 -30
- package/dist/Markdown/charts/ChartPre.d.ts +0 -6
- package/dist/Markdown/charts/chartHelpers.d.ts +0 -40
- package/dist/Markdown/plugins/remarkChart.d.ts +0 -59
- package/dist/index-DdRyk11n.js.map +0 -1
- package/dist/stories/Integration.stories.tsx +0 -312
- /package/dist/{Markdown/charts/chartHelpers.spec.d.ts → ComponentCatalog/chartComponentDef.spec.d.ts} +0 -0
package/dist/index.umd.cjs
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
}
|
|
12
12
|
})();
|
|
13
13
|
(function(global, factory) {
|
|
14
|
-
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react/jsx-runtime"), require("reablocks"), require("react"), require("motion/react"), require("@tiptap/react"), require("@floating-ui/dom"), require("@tiptap/extension-document"), require("@tiptap/extension-paragraph"), require("@tiptap/extension-text"), require("@tiptap/extension-hard-break"), require("@tiptap/extension-placeholder"), require("@tiptap/extension-mention"), require("@radix-ui/react-slot"), require("react-markdown"), require("react-syntax-highlighter"), require("rehype-katex"), require("rehype-raw"), require("reaviz"), require("mdast-util-find-and-replace"), require("
|
|
15
|
-
})(this, function(exports2, jsxRuntime, reablocks, React, react$1, react, dom, Document, Paragraph, Text, HardBreak, Placeholder, Mention, reactSlot, ReactMarkdown, reactSyntaxHighlighter, rehypeKatex, rehypeRaw, reaviz, mdastUtilFindAndReplace,
|
|
14
|
+
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react/jsx-runtime"), require("reablocks"), require("react"), require("motion/react"), require("@tiptap/react"), require("@floating-ui/dom"), require("@tiptap/extension-document"), require("@tiptap/extension-paragraph"), require("@tiptap/extension-text"), require("@tiptap/extension-hard-break"), require("@tiptap/extension-placeholder"), require("@tiptap/extension-mention"), require("@radix-ui/react-slot"), require("react-markdown"), require("react-syntax-highlighter"), require("rehype-katex"), require("rehype-raw"), require("reaviz"), require("mdast-util-find-and-replace"), require("lodash/debounce.js"), require("reakeys"), require("remark-gfm"), require("remark-youtube"), require("remark-math"), require("date-fns"), require("@floating-ui/react"), require("zod")) : typeof define === "function" && define.amd ? define(["exports", "react/jsx-runtime", "reablocks", "react", "motion/react", "@tiptap/react", "@floating-ui/dom", "@tiptap/extension-document", "@tiptap/extension-paragraph", "@tiptap/extension-text", "@tiptap/extension-hard-break", "@tiptap/extension-placeholder", "@tiptap/extension-mention", "@radix-ui/react-slot", "react-markdown", "react-syntax-highlighter", "rehype-katex", "rehype-raw", "reaviz", "mdast-util-find-and-replace", "lodash/debounce.js", "reakeys", "remark-gfm", "remark-youtube", "remark-math", "date-fns", "@floating-ui/react", "zod"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.reachat = {}, global.jsxRuntime, global.reablocks, global.React, global.react$1, global.react, global.dom, global.Document, global.Paragraph, global.Text, global.HardBreak, global.Placeholder, global.Mention, global.reactSlot, global.ReactMarkdown, global.reactSyntaxHighlighter, global.rehypeKatex, global.rehypeRaw, global.reaviz, global.mdastUtilFindAndReplace, global.debounce, global.reakeys, global.remarkGfm, global.remarkYoutube, global.remarkMath, global.dateFns, global.react$2, global.zod));
|
|
15
|
+
})(this, (function(exports2, jsxRuntime, reablocks, React, react$1, react, dom, Document, Paragraph, Text, HardBreak, Placeholder, Mention, reactSlot, ReactMarkdown, reactSyntaxHighlighter, rehypeKatex, rehypeRaw, reaviz, mdastUtilFindAndReplace, debounce, reakeys, remarkGfm, remarkYoutube, remarkMath, dateFns, react$2, zod) {
|
|
16
16
|
"use strict";
|
|
17
17
|
function _interopNamespaceDefault(e) {
|
|
18
18
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -70,10 +70,7 @@
|
|
|
70
70
|
variant: "text",
|
|
71
71
|
disabled: isLoading || disabled,
|
|
72
72
|
className: reablocks.cn(theme.input.upload),
|
|
73
|
-
onClick: () =>
|
|
74
|
-
var _a;
|
|
75
|
-
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
76
|
-
},
|
|
73
|
+
onClick: () => fileInputRef.current?.click(),
|
|
77
74
|
children: attachIcon
|
|
78
75
|
}
|
|
79
76
|
)
|
|
@@ -320,23 +317,24 @@
|
|
|
320
317
|
].join(" "),
|
|
321
318
|
title: "text-yellow-600 dark:text-yellow-400 text-sm font-medium mb-2"
|
|
322
319
|
}
|
|
320
|
+
},
|
|
321
|
+
component: {
|
|
322
|
+
base: "my-4"
|
|
323
323
|
}
|
|
324
324
|
};
|
|
325
325
|
const POPUP_STYLE = { zIndex: 9999 };
|
|
326
326
|
const MentionList = React.forwardRef(
|
|
327
327
|
({ items, command, triggerChar, config, query }, ref) => {
|
|
328
|
-
var _a;
|
|
329
328
|
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
330
329
|
const itemRefs = React.useRef([]);
|
|
331
330
|
const { theme } = React.useContext(ChatContext);
|
|
332
|
-
const popupTheme =
|
|
331
|
+
const popupTheme = theme?.input?.popup || chatTheme.input.popup;
|
|
333
332
|
React.useEffect(() => {
|
|
334
333
|
setSelectedIndex(0);
|
|
335
334
|
}, [items]);
|
|
336
335
|
React.useEffect(() => {
|
|
337
|
-
var _a2;
|
|
338
336
|
if (itemRefs.current[selectedIndex]) {
|
|
339
|
-
|
|
337
|
+
itemRefs.current[selectedIndex]?.scrollIntoView({
|
|
340
338
|
block: "nearest",
|
|
341
339
|
behavior: "smooth"
|
|
342
340
|
});
|
|
@@ -467,10 +465,7 @@
|
|
|
467
465
|
if (!query) return config.items.slice(0, config.maxResults || 10);
|
|
468
466
|
const lowerQuery = query.toLowerCase();
|
|
469
467
|
return config.items.filter(
|
|
470
|
-
(item) =>
|
|
471
|
-
var _a;
|
|
472
|
-
return item.label.toLowerCase().includes(lowerQuery) || ((_a = item.description) == null ? void 0 : _a.toLowerCase().includes(lowerQuery));
|
|
473
|
-
}
|
|
468
|
+
(item) => item.label.toLowerCase().includes(lowerQuery) || item.description?.toLowerCase().includes(lowerQuery)
|
|
474
469
|
).slice(0, config.maxResults || 10);
|
|
475
470
|
},
|
|
476
471
|
// Render callbacks for managing the popup lifecycle
|
|
@@ -497,7 +492,7 @@
|
|
|
497
492
|
},
|
|
498
493
|
// Called when query or items change
|
|
499
494
|
onUpdate: (props) => {
|
|
500
|
-
component
|
|
495
|
+
component?.updateProps({
|
|
501
496
|
...props,
|
|
502
497
|
triggerChar,
|
|
503
498
|
config
|
|
@@ -505,25 +500,23 @@
|
|
|
505
500
|
if (!props.clientRect) {
|
|
506
501
|
return;
|
|
507
502
|
}
|
|
508
|
-
if (component
|
|
503
|
+
if (component?.element) {
|
|
509
504
|
updatePopupPosition(props.editor, component.element);
|
|
510
505
|
}
|
|
511
506
|
},
|
|
512
507
|
// Handle keyboard navigation (Escape closes popup)
|
|
513
508
|
onKeyDown: (props) => {
|
|
514
|
-
var _a;
|
|
515
509
|
if (props.event.key === "Escape") {
|
|
516
|
-
component
|
|
510
|
+
component?.destroy();
|
|
517
511
|
return true;
|
|
518
512
|
}
|
|
519
|
-
return
|
|
513
|
+
return component?.ref?.onKeyDown(props) ?? false;
|
|
520
514
|
},
|
|
521
515
|
// Cleanup when suggestion is dismissed
|
|
522
516
|
onExit: () => {
|
|
523
|
-
var _a;
|
|
524
517
|
suggestionActiveRef.current = false;
|
|
525
|
-
|
|
526
|
-
component
|
|
518
|
+
component?.element?.remove();
|
|
519
|
+
component?.destroy();
|
|
527
520
|
}
|
|
528
521
|
};
|
|
529
522
|
}
|
|
@@ -543,12 +536,10 @@
|
|
|
543
536
|
onSubmit,
|
|
544
537
|
onChange
|
|
545
538
|
}, ref) => {
|
|
546
|
-
var _a, _b, _c, _d;
|
|
547
539
|
const { theme } = React.useContext(ChatContext);
|
|
548
540
|
const containerRef = React.useRef(null);
|
|
549
541
|
const suggestionActiveRef = React.useRef(false);
|
|
550
542
|
const extensions = React.useMemo(() => {
|
|
551
|
-
var _a2, _b2, _c2, _d2, _e, _f, _g, _h;
|
|
552
543
|
const exts = [
|
|
553
544
|
Document,
|
|
554
545
|
Paragraph.configure({
|
|
@@ -567,7 +558,7 @@
|
|
|
567
558
|
exts.push(
|
|
568
559
|
Mention.configure({
|
|
569
560
|
HTMLAttributes: {
|
|
570
|
-
class: reablocks.cn(
|
|
561
|
+
class: reablocks.cn(theme?.input?.tag?.base, theme?.input?.tag?.mention)
|
|
571
562
|
},
|
|
572
563
|
suggestion: createSuggestionConfig(
|
|
573
564
|
mentions,
|
|
@@ -583,7 +574,7 @@
|
|
|
583
574
|
exts.push(
|
|
584
575
|
Mention.configure({
|
|
585
576
|
HTMLAttributes: {
|
|
586
|
-
class: reablocks.cn(
|
|
577
|
+
class: reablocks.cn(theme?.input?.tag?.base, theme?.input?.tag?.command)
|
|
587
578
|
},
|
|
588
579
|
suggestion: createSuggestionConfig(
|
|
589
580
|
commands,
|
|
@@ -604,13 +595,13 @@
|
|
|
604
595
|
immediatelyRender: false,
|
|
605
596
|
onUpdate: ({ editor: editor2 }) => {
|
|
606
597
|
const text = editor2.getText();
|
|
607
|
-
onChange
|
|
598
|
+
onChange?.(text);
|
|
608
599
|
},
|
|
609
600
|
editorProps: {
|
|
610
601
|
attributes: {
|
|
611
602
|
class: reablocks.cn(
|
|
612
|
-
|
|
613
|
-
|
|
603
|
+
theme?.input?.editor?.base,
|
|
604
|
+
theme?.input?.editor?.placeholder
|
|
614
605
|
),
|
|
615
606
|
style: `min-height: ${minHeight}px; max-height: ${maxHeight}px;`,
|
|
616
607
|
role: "textbox",
|
|
@@ -628,7 +619,7 @@
|
|
|
628
619
|
if (text.trim() && onSubmit) {
|
|
629
620
|
event.preventDefault();
|
|
630
621
|
onSubmit(text);
|
|
631
|
-
editor
|
|
622
|
+
editor?.commands.clearContent();
|
|
632
623
|
return true;
|
|
633
624
|
}
|
|
634
625
|
}
|
|
@@ -645,16 +636,16 @@
|
|
|
645
636
|
}, [editor, autoFocus]);
|
|
646
637
|
React.useImperativeHandle(ref, () => ({
|
|
647
638
|
focus: () => {
|
|
648
|
-
editor
|
|
639
|
+
editor?.commands.focus();
|
|
649
640
|
},
|
|
650
641
|
getValue: () => {
|
|
651
|
-
return
|
|
642
|
+
return editor?.getText() || "";
|
|
652
643
|
},
|
|
653
644
|
setValue: (newValue) => {
|
|
654
|
-
editor
|
|
645
|
+
editor?.commands.setContent(newValue ? `<p>${newValue}</p>` : "");
|
|
655
646
|
},
|
|
656
647
|
insertText: (text) => {
|
|
657
|
-
editor
|
|
648
|
+
editor?.commands.insertContent(text);
|
|
658
649
|
}
|
|
659
650
|
}));
|
|
660
651
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: reablocks.cn("relative w-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(react.EditorContent, { editor }) });
|
|
@@ -688,43 +679,37 @@
|
|
|
688
679
|
const inputRef = React.useRef(null);
|
|
689
680
|
const containerRef = React.useRef(null);
|
|
690
681
|
React.useEffect(() => {
|
|
691
|
-
var _a;
|
|
692
682
|
if (autoFocus) {
|
|
693
|
-
|
|
683
|
+
inputRef.current?.focus();
|
|
694
684
|
}
|
|
695
685
|
}, [activeSessionId, autoFocus]);
|
|
696
686
|
React.useImperativeHandle(ref, () => ({
|
|
697
687
|
focus: () => {
|
|
698
|
-
|
|
699
|
-
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
688
|
+
inputRef.current?.focus();
|
|
700
689
|
},
|
|
701
690
|
getValue: () => {
|
|
702
|
-
|
|
703
|
-
return ((_a = inputRef.current) == null ? void 0 : _a.getValue()) || "";
|
|
691
|
+
return inputRef.current?.getValue() || "";
|
|
704
692
|
},
|
|
705
693
|
setValue: (value) => {
|
|
706
|
-
var _a;
|
|
707
694
|
setMessage(value);
|
|
708
|
-
|
|
695
|
+
inputRef.current?.setValue(value);
|
|
709
696
|
},
|
|
710
697
|
insertText: (text) => {
|
|
711
|
-
|
|
712
|
-
(_a = inputRef.current) == null ? void 0 : _a.insertText(text);
|
|
698
|
+
inputRef.current?.insertText(text);
|
|
713
699
|
}
|
|
714
700
|
}));
|
|
715
701
|
const handleSendMessage = React.useCallback(() => {
|
|
716
|
-
|
|
717
|
-
const currentMessage = (_a = inputRef.current) == null ? void 0 : _a.getValue();
|
|
702
|
+
const currentMessage = inputRef.current?.getValue();
|
|
718
703
|
if (currentMessage.trim()) {
|
|
719
|
-
sendMessage
|
|
704
|
+
sendMessage?.(currentMessage);
|
|
720
705
|
setMessage("");
|
|
721
|
-
|
|
706
|
+
inputRef.current?.setValue("");
|
|
722
707
|
}
|
|
723
708
|
}, [sendMessage]);
|
|
724
709
|
const handleSubmit = React.useCallback(
|
|
725
710
|
(value) => {
|
|
726
711
|
if (value.trim()) {
|
|
727
|
-
sendMessage
|
|
712
|
+
sendMessage?.(value);
|
|
728
713
|
setMessage("");
|
|
729
714
|
}
|
|
730
715
|
},
|
|
@@ -735,8 +720,7 @@
|
|
|
735
720
|
}, []);
|
|
736
721
|
const handleFileUpload = React.useCallback(
|
|
737
722
|
(event) => {
|
|
738
|
-
|
|
739
|
-
const file = (_a = event.target.files) == null ? void 0 : _a[0];
|
|
723
|
+
const file = event.target.files?.[0];
|
|
740
724
|
if (file && fileUpload) {
|
|
741
725
|
fileUpload(file);
|
|
742
726
|
}
|
|
@@ -770,7 +754,7 @@
|
|
|
770
754
|
}
|
|
771
755
|
),
|
|
772
756
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: reablocks.cn(theme.input.actions.base), children: [
|
|
773
|
-
|
|
757
|
+
allowedFiles?.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
774
758
|
FileInput,
|
|
775
759
|
{
|
|
776
760
|
allowedFiles,
|
|
@@ -1880,7 +1864,7 @@
|
|
|
1880
1864
|
toolbarClassName,
|
|
1881
1865
|
theme = dark
|
|
1882
1866
|
}) => {
|
|
1883
|
-
const match = language
|
|
1867
|
+
const match = language?.match(/language-(\w+)/);
|
|
1884
1868
|
const lang = match ? match[1] : "text";
|
|
1885
1869
|
const handleCopy = (text) => {
|
|
1886
1870
|
navigator.clipboard.writeText(text).then(() => {
|
|
@@ -1963,14 +1947,16 @@
|
|
|
1963
1947
|
li: (props) => /* @__PURE__ */ jsxRuntime.jsx("li", { ...props, className: reablocks.cn(theme.messages.message.markdown.li) }),
|
|
1964
1948
|
ul: (props) => /* @__PURE__ */ jsxRuntime.jsx("ul", { ...props, className: reablocks.cn(theme.messages.message.markdown.ul) }),
|
|
1965
1949
|
ol: (props) => /* @__PURE__ */ jsxRuntime.jsx("ol", { ...props, className: reablocks.cn(theme.messages.message.markdown.ol) }),
|
|
1966
|
-
redact
|
|
1950
|
+
// 'redact' is a custom element created by remarkRedact, not a standard
|
|
1951
|
+
// HTML tag, so it falls outside react-markdown's Components type.
|
|
1952
|
+
redact: ((props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1967
1953
|
reablocks.Redact,
|
|
1968
1954
|
{
|
|
1969
1955
|
value: props["data-redact-value"] || props.children,
|
|
1970
1956
|
allowToggle: true,
|
|
1971
1957
|
tooltipText: `${props["data-redact-name"] || "Sensitive"} information - Click to toggle`
|
|
1972
1958
|
}
|
|
1973
|
-
)
|
|
1959
|
+
))
|
|
1974
1960
|
};
|
|
1975
1961
|
return {
|
|
1976
1962
|
...defaultComponents,
|
|
@@ -1988,7 +1974,7 @@
|
|
|
1988
1974
|
}
|
|
1989
1975
|
);
|
|
1990
1976
|
};
|
|
1991
|
-
const
|
|
1977
|
+
const ComponentError = ({
|
|
1992
1978
|
variant = "error",
|
|
1993
1979
|
title,
|
|
1994
1980
|
message,
|
|
@@ -2016,12 +2002,12 @@
|
|
|
2016
2002
|
data: d.data
|
|
2017
2003
|
}));
|
|
2018
2004
|
if (!chartData || chartData.length === 0) {
|
|
2019
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2005
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ComponentError, { variant: "warning", message: "No chart data available" });
|
|
2020
2006
|
}
|
|
2021
2007
|
for (const point of chartData) {
|
|
2022
2008
|
if (typeof point.data !== "number" || isNaN(point.data)) {
|
|
2023
2009
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2024
|
-
|
|
2010
|
+
ComponentError,
|
|
2025
2011
|
{
|
|
2026
2012
|
message: `Invalid data point: ${JSON.stringify(point)}`
|
|
2027
2013
|
}
|
|
@@ -2090,10 +2076,10 @@
|
|
|
2090
2076
|
case "sparkline":
|
|
2091
2077
|
return /* @__PURE__ */ jsxRuntime.jsx(reaviz.SparklineChart, { width, height, data: chartData });
|
|
2092
2078
|
default:
|
|
2093
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2079
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ComponentError, { message: `Unknown chart type: ${type}` });
|
|
2094
2080
|
}
|
|
2095
2081
|
} catch (error) {
|
|
2096
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2082
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ComponentError, { message: `Chart render error: ${String(error)}` });
|
|
2097
2083
|
}
|
|
2098
2084
|
}, [type, data, width, height]);
|
|
2099
2085
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: reablocks.cn(theme.chart.base, className), children: [
|
|
@@ -2101,93 +2087,6 @@
|
|
|
2101
2087
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: theme.chart.content, children: chartElement })
|
|
2102
2088
|
] });
|
|
2103
2089
|
};
|
|
2104
|
-
function validateChartData(data) {
|
|
2105
|
-
if (!Array.isArray(data)) {
|
|
2106
|
-
return null;
|
|
2107
|
-
}
|
|
2108
|
-
const validData = [];
|
|
2109
|
-
for (const item of data) {
|
|
2110
|
-
if (item && typeof item === "object" && "key" in item && "data" in item && typeof item.data === "number") {
|
|
2111
|
-
validData.push({
|
|
2112
|
-
key: String(item.key),
|
|
2113
|
-
data: item.data
|
|
2114
|
-
});
|
|
2115
|
-
} else {
|
|
2116
|
-
return null;
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
return validData.length > 0 ? validData : null;
|
|
2120
|
-
}
|
|
2121
|
-
function parseChartConfig(value) {
|
|
2122
|
-
try {
|
|
2123
|
-
const config = JSON.parse(value);
|
|
2124
|
-
if (!config || !config.type || !config.data) {
|
|
2125
|
-
return null;
|
|
2126
|
-
}
|
|
2127
|
-
const validData = validateChartData(config.data);
|
|
2128
|
-
if (!validData) {
|
|
2129
|
-
console.warn("parseChartConfig: Invalid chart data format");
|
|
2130
|
-
return null;
|
|
2131
|
-
}
|
|
2132
|
-
return {
|
|
2133
|
-
...config,
|
|
2134
|
-
data: validData
|
|
2135
|
-
};
|
|
2136
|
-
} catch (error) {
|
|
2137
|
-
console.warn("parseChartConfig: Failed to parse JSON", error);
|
|
2138
|
-
return null;
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
function isChartClassName(className) {
|
|
2142
|
-
return className === "language-chart";
|
|
2143
|
-
}
|
|
2144
|
-
function getChildText(children) {
|
|
2145
|
-
if (children === null || children === void 0) {
|
|
2146
|
-
return "";
|
|
2147
|
-
}
|
|
2148
|
-
if (typeof children === "string") {
|
|
2149
|
-
return children;
|
|
2150
|
-
}
|
|
2151
|
-
if (typeof children === "number") {
|
|
2152
|
-
return String(children);
|
|
2153
|
-
}
|
|
2154
|
-
if (Array.isArray(children)) {
|
|
2155
|
-
return children.map(getChildText).join("");
|
|
2156
|
-
}
|
|
2157
|
-
if (typeof children === "object") {
|
|
2158
|
-
if ("props" in children && children.props) {
|
|
2159
|
-
const element = children;
|
|
2160
|
-
return getChildText(element.props.children);
|
|
2161
|
-
}
|
|
2162
|
-
}
|
|
2163
|
-
return "";
|
|
2164
|
-
}
|
|
2165
|
-
const ChartPre = ({ children, ...props }) => {
|
|
2166
|
-
var _a, _b;
|
|
2167
|
-
if (children && typeof children === "object" && "props" in children) {
|
|
2168
|
-
const codeElement = children;
|
|
2169
|
-
if (isChartClassName((_a = codeElement.props) == null ? void 0 : _a.className)) {
|
|
2170
|
-
const codeContent = getChildText((_b = codeElement.props) == null ? void 0 : _b.children);
|
|
2171
|
-
if (codeContent) {
|
|
2172
|
-
const chartConfig = parseChartConfig(codeContent);
|
|
2173
|
-
if (chartConfig) {
|
|
2174
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChartRenderer, { config: chartConfig });
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2178
|
-
ChartError,
|
|
2179
|
-
{
|
|
2180
|
-
title: "Failed to parse chart configuration",
|
|
2181
|
-
code: codeContent || "No content"
|
|
2182
|
-
}
|
|
2183
|
-
);
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
return /* @__PURE__ */ jsxRuntime.jsx("pre", { ...props, children });
|
|
2187
|
-
};
|
|
2188
|
-
const chartComponents = {
|
|
2189
|
-
pre: ChartPre
|
|
2190
|
-
};
|
|
2191
2090
|
const CVE_REGEX = /(CVE-(19|20)\d{2}-\d{4,7})/gi;
|
|
2192
2091
|
function remarkCve() {
|
|
2193
2092
|
return (tree, _file) => {
|
|
@@ -2208,31 +2107,8 @@
|
|
|
2208
2107
|
];
|
|
2209
2108
|
}
|
|
2210
2109
|
}
|
|
2211
|
-
const
|
|
2212
|
-
|
|
2213
|
-
return (tree) => {
|
|
2214
|
-
unistUtilVisit.visit(tree, "code", (node) => {
|
|
2215
|
-
if (node.lang !== "chart") {
|
|
2216
|
-
return;
|
|
2217
|
-
}
|
|
2218
|
-
try {
|
|
2219
|
-
const config = JSON.parse(node.value);
|
|
2220
|
-
if (!config.type || !config.data) {
|
|
2221
|
-
console.warn(
|
|
2222
|
-
"remarkChart: Invalid chart config - missing type or data"
|
|
2223
|
-
);
|
|
2224
|
-
return;
|
|
2225
|
-
}
|
|
2226
|
-
const chartConfig = {
|
|
2227
|
-
...config,
|
|
2228
|
-
width: config.width ?? defaultWidth,
|
|
2229
|
-
height: config.height ?? defaultHeight
|
|
2230
|
-
};
|
|
2231
|
-
node.value = JSON.stringify(chartConfig);
|
|
2232
|
-
} catch (error) {
|
|
2233
|
-
console.warn("remarkChart: Failed to parse chart config:", error);
|
|
2234
|
-
}
|
|
2235
|
-
});
|
|
2110
|
+
const remarkComponent = (_options = {}) => {
|
|
2111
|
+
return () => {
|
|
2236
2112
|
};
|
|
2237
2113
|
};
|
|
2238
2114
|
function remarkRedact(matchers) {
|
|
@@ -2307,7 +2183,7 @@
|
|
|
2307
2183
|
}) => {
|
|
2308
2184
|
const { theme } = React.useContext(ChatContext);
|
|
2309
2185
|
const FileRenderer = React.useMemo(() => {
|
|
2310
|
-
const Renderer = Object.keys(FILE_TYPE_RENDERER_MAP).find((key) => type
|
|
2186
|
+
const Renderer = Object.keys(FILE_TYPE_RENDERER_MAP).find((key) => type?.startsWith(key)) ?? "default";
|
|
2311
2187
|
return FILE_TYPE_RENDERER_MAP[Renderer] || DefaultFileRenderer$2;
|
|
2312
2188
|
}, [type]);
|
|
2313
2189
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2491,8 +2367,7 @@
|
|
|
2491
2367
|
}
|
|
2492
2368
|
return files.reduce(
|
|
2493
2369
|
(acc, file) => {
|
|
2494
|
-
|
|
2495
|
-
if ((_a = file.type) == null ? void 0 : _a.startsWith("image/")) {
|
|
2370
|
+
if (file.type?.startsWith("image/")) {
|
|
2496
2371
|
acc.imageFiles.push(file);
|
|
2497
2372
|
} else {
|
|
2498
2373
|
acc.otherFiles.push(file);
|
|
@@ -2794,7 +2669,6 @@ ${response}` : ""}`);
|
|
|
2794
2669
|
showMoreText = "Show more",
|
|
2795
2670
|
showScrollBottomButton = false
|
|
2796
2671
|
}) => {
|
|
2797
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2798
2672
|
const { activeSession, theme } = React.useContext(ChatContext);
|
|
2799
2673
|
const contentRef = React.useRef(null);
|
|
2800
2674
|
const messagesRef = React.useRef(null);
|
|
@@ -2835,7 +2709,7 @@ ${response}` : ""}`);
|
|
|
2835
2709
|
}
|
|
2836
2710
|
};
|
|
2837
2711
|
const reversedConvos = React.useMemo(
|
|
2838
|
-
() => [...
|
|
2712
|
+
() => [...activeSession?.conversations ?? []].reverse(),
|
|
2839
2713
|
[activeSession]
|
|
2840
2714
|
);
|
|
2841
2715
|
const { data, hasMore, showNext } = reablocks.useInfinityList({
|
|
@@ -2843,7 +2717,7 @@ ${response}` : ""}`);
|
|
|
2843
2717
|
size: limit
|
|
2844
2718
|
});
|
|
2845
2719
|
const reReversedConvo = React.useMemo(() => [...data].reverse(), [data]);
|
|
2846
|
-
const convosToRender = limit ? reReversedConvo : activeSession
|
|
2720
|
+
const convosToRender = limit ? reReversedConvo : activeSession?.conversations;
|
|
2847
2721
|
if (!activeSession) {
|
|
2848
2722
|
return /* @__PURE__ */ jsxRuntime.jsx(SessionEmpty, { children: newSessionContent });
|
|
2849
2723
|
}
|
|
@@ -2853,7 +2727,7 @@ ${response}` : ""}`);
|
|
|
2853
2727
|
{
|
|
2854
2728
|
className: reablocks.cn(theme.messages.content, "h-full"),
|
|
2855
2729
|
ref: contentRef,
|
|
2856
|
-
id: activeSession
|
|
2730
|
+
id: activeSession?.id,
|
|
2857
2731
|
children: [
|
|
2858
2732
|
hasMore && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2859
2733
|
reablocks.Button,
|
|
@@ -2887,7 +2761,7 @@ ${response}` : ""}`);
|
|
|
2887
2761
|
conversation.id
|
|
2888
2762
|
))
|
|
2889
2763
|
},
|
|
2890
|
-
activeSession
|
|
2764
|
+
activeSession?.id
|
|
2891
2765
|
) })
|
|
2892
2766
|
]
|
|
2893
2767
|
}
|
|
@@ -2899,12 +2773,12 @@ ${response}` : ""}`);
|
|
|
2899
2773
|
animate: { y: 0, opacity: 1 },
|
|
2900
2774
|
exit: { y: 100, opacity: 0 },
|
|
2901
2775
|
transition: { duration: 0.3, ease: "easeOut" },
|
|
2902
|
-
className:
|
|
2776
|
+
className: theme.messages?.message?.scrollToBottom?.container,
|
|
2903
2777
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2904
2778
|
reablocks.IconButton,
|
|
2905
2779
|
{
|
|
2906
2780
|
onClick: handleScrollToBottom,
|
|
2907
|
-
className:
|
|
2781
|
+
className: theme.messages?.message?.scrollToBottom?.button,
|
|
2908
2782
|
size: "sm",
|
|
2909
2783
|
children: /* @__PURE__ */ jsxRuntime.jsx(SvgArrowDown, {})
|
|
2910
2784
|
}
|
|
@@ -2960,6 +2834,7 @@ ${response}` : ""}`);
|
|
|
2960
2834
|
onNewSession,
|
|
2961
2835
|
remarkPlugins = defaultRemarkPlugins,
|
|
2962
2836
|
markdownComponents,
|
|
2837
|
+
components: componentCatalog2,
|
|
2963
2838
|
disabled,
|
|
2964
2839
|
style,
|
|
2965
2840
|
className
|
|
@@ -2974,20 +2849,20 @@ ${response}` : ""}`);
|
|
|
2974
2849
|
const handleSelectSession = React.useCallback(
|
|
2975
2850
|
(sessionId) => {
|
|
2976
2851
|
setInternalActiveSessionID(sessionId);
|
|
2977
|
-
onSelectSession
|
|
2852
|
+
onSelectSession?.(sessionId);
|
|
2978
2853
|
},
|
|
2979
2854
|
[onSelectSession]
|
|
2980
2855
|
);
|
|
2981
2856
|
const handleDeleteSession = React.useCallback(
|
|
2982
2857
|
(sessionId) => {
|
|
2983
2858
|
setInternalActiveSessionID(void 0);
|
|
2984
|
-
onDeleteSession
|
|
2859
|
+
onDeleteSession?.(sessionId);
|
|
2985
2860
|
},
|
|
2986
2861
|
[onDeleteSession]
|
|
2987
2862
|
);
|
|
2988
2863
|
const handleCreateNewSession = React.useCallback(() => {
|
|
2989
2864
|
setInternalActiveSessionID(void 0);
|
|
2990
|
-
onNewSession
|
|
2865
|
+
onNewSession?.();
|
|
2991
2866
|
}, [onNewSession]);
|
|
2992
2867
|
reakeys.useHotkeys([
|
|
2993
2868
|
{
|
|
@@ -3004,12 +2879,23 @@ ${response}` : ""}`);
|
|
|
3004
2879
|
() => sessions.find((session) => session.id === internalActiveSessionID),
|
|
3005
2880
|
[sessions, internalActiveSessionID]
|
|
3006
2881
|
);
|
|
2882
|
+
const mergedRemarkPlugins = React.useMemo(() => {
|
|
2883
|
+
if (!componentCatalog2) return remarkPlugins;
|
|
2884
|
+
return [...remarkPlugins, componentCatalog2.remarkPlugin];
|
|
2885
|
+
}, [remarkPlugins, componentCatalog2]);
|
|
2886
|
+
const mergedMarkdownComponents = React.useMemo(() => {
|
|
2887
|
+
if (!componentCatalog2) return markdownComponents;
|
|
2888
|
+
return {
|
|
2889
|
+
...componentCatalog2.components,
|
|
2890
|
+
...markdownComponents
|
|
2891
|
+
};
|
|
2892
|
+
}, [markdownComponents, componentCatalog2]);
|
|
3007
2893
|
const contextValue = React.useMemo(
|
|
3008
2894
|
() => ({
|
|
3009
2895
|
sessions,
|
|
3010
2896
|
activeSession,
|
|
3011
|
-
remarkPlugins,
|
|
3012
|
-
markdownComponents,
|
|
2897
|
+
remarkPlugins: mergedRemarkPlugins,
|
|
2898
|
+
markdownComponents: mergedMarkdownComponents,
|
|
3013
2899
|
theme,
|
|
3014
2900
|
disabled,
|
|
3015
2901
|
isLoading,
|
|
@@ -3029,8 +2915,8 @@ ${response}` : ""}`);
|
|
|
3029
2915
|
viewType,
|
|
3030
2916
|
disabled,
|
|
3031
2917
|
theme,
|
|
3032
|
-
|
|
3033
|
-
|
|
2918
|
+
mergedRemarkPlugins,
|
|
2919
|
+
mergedMarkdownComponents,
|
|
3034
2920
|
sessions,
|
|
3035
2921
|
activeSession,
|
|
3036
2922
|
internalActiveSessionID,
|
|
@@ -3069,7 +2955,7 @@ ${response}` : ""}`);
|
|
|
3069
2955
|
const { activeSessionId, selectSession, deleteSession, theme } = React.useContext(ChatContext);
|
|
3070
2956
|
const Comp = children ? reactSlot.Slot : reablocks.ListItem;
|
|
3071
2957
|
const handleSelect = React.useCallback(() => {
|
|
3072
|
-
selectSession
|
|
2958
|
+
selectSession?.(session.id);
|
|
3073
2959
|
}, [selectSession, session.id]);
|
|
3074
2960
|
const handleDelete = React.useCallback(
|
|
3075
2961
|
(e) => {
|
|
@@ -3131,7 +3017,7 @@ ${response}` : ""}`);
|
|
|
3131
3017
|
}),
|
|
3132
3018
|
children: [
|
|
3133
3019
|
/* @__PURE__ */ jsxRuntime.jsx(reablocks.List, { children }),
|
|
3134
|
-
templates && !activeSessionId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: templates.map((template) => /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: () => createSession
|
|
3020
|
+
templates && !activeSessionId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: templates.map((template) => /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: () => createSession?.(), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3135
3021
|
SessionListItem,
|
|
3136
3022
|
{
|
|
3137
3023
|
session: {
|
|
@@ -3160,7 +3046,7 @@ ${response}` : ""}`);
|
|
|
3160
3046
|
fullWidth: true,
|
|
3161
3047
|
disableMargins: true,
|
|
3162
3048
|
color: "primary",
|
|
3163
|
-
|
|
3049
|
+
start: /* @__PURE__ */ jsxRuntime.jsx(SvgPlus, {}),
|
|
3164
3050
|
className: reablocks.cn(theme.sessions.create),
|
|
3165
3051
|
disabled,
|
|
3166
3052
|
onClick: createSession,
|
|
@@ -3296,7 +3182,7 @@ ${response}` : ""}`);
|
|
|
3296
3182
|
const { theme, disabled, isLoading } = React.useContext(ChatContext);
|
|
3297
3183
|
const handleClick = () => {
|
|
3298
3184
|
if (disabled || isLoading) return;
|
|
3299
|
-
onClick
|
|
3185
|
+
onClick?.(content);
|
|
3300
3186
|
};
|
|
3301
3187
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3302
3188
|
reablocks.Button,
|
|
@@ -3549,8 +3435,7 @@ ${response}` : ""}`);
|
|
|
3549
3435
|
return null;
|
|
3550
3436
|
}
|
|
3551
3437
|
async function* parseSSE(response, signal) {
|
|
3552
|
-
|
|
3553
|
-
const reader = (_a = response.body) == null ? void 0 : _a.getReader();
|
|
3438
|
+
const reader = response.body?.getReader();
|
|
3554
3439
|
if (!reader) {
|
|
3555
3440
|
throw new Error("Response body is not readable");
|
|
3556
3441
|
}
|
|
@@ -3602,8 +3487,7 @@ ${response}` : ""}`);
|
|
|
3602
3487
|
onEventRef.current = onEvent;
|
|
3603
3488
|
React.useEffect(() => {
|
|
3604
3489
|
return () => {
|
|
3605
|
-
|
|
3606
|
-
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
3490
|
+
abortRef.current?.abort();
|
|
3607
3491
|
};
|
|
3608
3492
|
}, []);
|
|
3609
3493
|
const selectSession = React.useCallback((sessionId) => {
|
|
@@ -3631,15 +3515,13 @@ ${response}` : ""}`);
|
|
|
3631
3515
|
setActiveSessionId(id);
|
|
3632
3516
|
}, []);
|
|
3633
3517
|
const stopMessage = React.useCallback(() => {
|
|
3634
|
-
|
|
3635
|
-
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
3518
|
+
abortRef.current?.abort();
|
|
3636
3519
|
abortRef.current = null;
|
|
3637
3520
|
setIsLoading(false);
|
|
3638
3521
|
}, []);
|
|
3639
3522
|
const sendMessage = React.useCallback(
|
|
3640
3523
|
async (message) => {
|
|
3641
|
-
|
|
3642
|
-
(_a = abortRef.current) == null ? void 0 : _a.abort();
|
|
3524
|
+
abortRef.current?.abort();
|
|
3643
3525
|
const abortController = new AbortController();
|
|
3644
3526
|
abortRef.current = abortController;
|
|
3645
3527
|
let sessionId = activeSessionId;
|
|
@@ -3666,7 +3548,7 @@ ${response}` : ""}`);
|
|
|
3666
3548
|
);
|
|
3667
3549
|
setIsLoading(true);
|
|
3668
3550
|
const currentSession = [
|
|
3669
|
-
...
|
|
3551
|
+
...sessions.find((s) => s.id === sessionId)?.conversations ?? []
|
|
3670
3552
|
];
|
|
3671
3553
|
const historyMessages = sessionsToAgUiMessages({
|
|
3672
3554
|
conversations: currentSession
|
|
@@ -3714,11 +3596,11 @@ ${response}` : ""}`);
|
|
|
3714
3596
|
abortController.signal
|
|
3715
3597
|
)) {
|
|
3716
3598
|
if (eventOrError instanceof Error) {
|
|
3717
|
-
|
|
3599
|
+
onErrorRef.current?.(eventOrError);
|
|
3718
3600
|
continue;
|
|
3719
3601
|
}
|
|
3720
3602
|
const event = eventOrError;
|
|
3721
|
-
|
|
3603
|
+
onEventRef.current?.(event);
|
|
3722
3604
|
switch (event.type) {
|
|
3723
3605
|
case AgUiEventType.TEXT_MESSAGE_CONTENT: {
|
|
3724
3606
|
responseText += event.delta;
|
|
@@ -3763,7 +3645,7 @@ ${response}` : ""}`);
|
|
|
3763
3645
|
}
|
|
3764
3646
|
case AgUiEventType.RUN_ERROR: {
|
|
3765
3647
|
const err = new Error(event.message);
|
|
3766
|
-
|
|
3648
|
+
onErrorRef.current?.(err);
|
|
3767
3649
|
break;
|
|
3768
3650
|
}
|
|
3769
3651
|
case AgUiEventType.RUN_FINISHED: {
|
|
@@ -3776,7 +3658,7 @@ ${response}` : ""}`);
|
|
|
3776
3658
|
return;
|
|
3777
3659
|
}
|
|
3778
3660
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
3779
|
-
|
|
3661
|
+
onErrorRef.current?.(error);
|
|
3780
3662
|
} finally {
|
|
3781
3663
|
if (abortRef.current === abortController) {
|
|
3782
3664
|
abortRef.current = null;
|
|
@@ -3797,10 +3679,420 @@ ${response}` : ""}`);
|
|
|
3797
3679
|
stopMessage
|
|
3798
3680
|
};
|
|
3799
3681
|
}
|
|
3682
|
+
function validateSpec(raw, definitions) {
|
|
3683
|
+
let parsed;
|
|
3684
|
+
try {
|
|
3685
|
+
parsed = JSON.parse(raw);
|
|
3686
|
+
} catch {
|
|
3687
|
+
return {
|
|
3688
|
+
ok: false,
|
|
3689
|
+
error: {
|
|
3690
|
+
type: "invalid_json",
|
|
3691
|
+
message: "Failed to parse component JSON",
|
|
3692
|
+
raw
|
|
3693
|
+
}
|
|
3694
|
+
};
|
|
3695
|
+
}
|
|
3696
|
+
const specArray = Array.isArray(parsed) ? parsed : [parsed];
|
|
3697
|
+
const validated = [];
|
|
3698
|
+
for (const item of specArray) {
|
|
3699
|
+
const result = validateSingleSpec(item, raw, definitions);
|
|
3700
|
+
if (!result.ok) {
|
|
3701
|
+
return { ok: false, error: result.error };
|
|
3702
|
+
}
|
|
3703
|
+
validated.push(result.spec);
|
|
3704
|
+
}
|
|
3705
|
+
return { ok: true, specs: validated };
|
|
3706
|
+
}
|
|
3707
|
+
function validateSingleSpec(item, raw, definitions) {
|
|
3708
|
+
if (!item || typeof item !== "object" || !("type" in item)) {
|
|
3709
|
+
return {
|
|
3710
|
+
ok: false,
|
|
3711
|
+
error: {
|
|
3712
|
+
type: "invalid_json",
|
|
3713
|
+
message: 'Component spec must be an object with a "type" field',
|
|
3714
|
+
raw
|
|
3715
|
+
}
|
|
3716
|
+
};
|
|
3717
|
+
}
|
|
3718
|
+
const spec = item;
|
|
3719
|
+
if (typeof spec.type !== "string") {
|
|
3720
|
+
return {
|
|
3721
|
+
ok: false,
|
|
3722
|
+
error: {
|
|
3723
|
+
type: "invalid_json",
|
|
3724
|
+
message: '"type" must be a string',
|
|
3725
|
+
raw
|
|
3726
|
+
}
|
|
3727
|
+
};
|
|
3728
|
+
}
|
|
3729
|
+
const componentType = spec.type;
|
|
3730
|
+
const definition = definitions[componentType];
|
|
3731
|
+
if (!definition) {
|
|
3732
|
+
return {
|
|
3733
|
+
ok: false,
|
|
3734
|
+
error: {
|
|
3735
|
+
type: "unknown_component",
|
|
3736
|
+
message: `Unknown component "${componentType}". Available: ${Object.keys(definitions).join(", ")}`,
|
|
3737
|
+
raw,
|
|
3738
|
+
componentType
|
|
3739
|
+
}
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3742
|
+
const props = spec.props && typeof spec.props === "object" && !Array.isArray(spec.props) ? spec.props : {};
|
|
3743
|
+
const parseResult = definition.props.safeParse(props);
|
|
3744
|
+
if (!parseResult.success) {
|
|
3745
|
+
return {
|
|
3746
|
+
ok: false,
|
|
3747
|
+
error: {
|
|
3748
|
+
type: "invalid_props",
|
|
3749
|
+
message: `Invalid props for "${componentType}": ${parseResult.error.issues.map((i) => i.message).join(", ")}`,
|
|
3750
|
+
raw,
|
|
3751
|
+
componentType,
|
|
3752
|
+
issues: parseResult.error.issues.map((i) => ({
|
|
3753
|
+
message: i.message,
|
|
3754
|
+
path: i.path
|
|
3755
|
+
}))
|
|
3756
|
+
}
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
let validatedChildren;
|
|
3760
|
+
if (spec.children) {
|
|
3761
|
+
if (!Array.isArray(spec.children)) {
|
|
3762
|
+
return {
|
|
3763
|
+
ok: false,
|
|
3764
|
+
error: {
|
|
3765
|
+
type: "invalid_json",
|
|
3766
|
+
message: '"children" must be an array',
|
|
3767
|
+
raw,
|
|
3768
|
+
componentType
|
|
3769
|
+
}
|
|
3770
|
+
};
|
|
3771
|
+
}
|
|
3772
|
+
validatedChildren = [];
|
|
3773
|
+
for (const child of spec.children) {
|
|
3774
|
+
const childResult = validateSingleSpec(child, raw, definitions);
|
|
3775
|
+
if (!childResult.ok) {
|
|
3776
|
+
return childResult;
|
|
3777
|
+
}
|
|
3778
|
+
validatedChildren.push(childResult.spec);
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
return {
|
|
3782
|
+
ok: true,
|
|
3783
|
+
spec: {
|
|
3784
|
+
type: componentType,
|
|
3785
|
+
props: parseResult.data,
|
|
3786
|
+
...validatedChildren ? { children: validatedChildren } : {}
|
|
3787
|
+
}
|
|
3788
|
+
};
|
|
3789
|
+
}
|
|
3790
|
+
const ComponentRenderer = ({
|
|
3791
|
+
raw,
|
|
3792
|
+
definitions,
|
|
3793
|
+
options
|
|
3794
|
+
}) => {
|
|
3795
|
+
const { theme, sendMessage } = React.useContext(ChatContext);
|
|
3796
|
+
const result = React.useMemo(
|
|
3797
|
+
() => validateSpec(raw, definitions),
|
|
3798
|
+
[raw, definitions]
|
|
3799
|
+
);
|
|
3800
|
+
if (!result.ok) {
|
|
3801
|
+
const error = result.error;
|
|
3802
|
+
const custom = options?.onError?.(error);
|
|
3803
|
+
if (custom !== void 0) {
|
|
3804
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: custom });
|
|
3805
|
+
}
|
|
3806
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3807
|
+
ComponentError,
|
|
3808
|
+
{
|
|
3809
|
+
title: errorTitle(error.type),
|
|
3810
|
+
message: error.message,
|
|
3811
|
+
code: error.raw
|
|
3812
|
+
}
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
const specs = result.specs;
|
|
3816
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: theme.component?.base, children: specs.map((spec, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3817
|
+
SpecRenderer,
|
|
3818
|
+
{
|
|
3819
|
+
spec,
|
|
3820
|
+
definitions,
|
|
3821
|
+
options,
|
|
3822
|
+
sendMessage
|
|
3823
|
+
},
|
|
3824
|
+
`${spec.type}-${index}-${stableKey(spec)}`
|
|
3825
|
+
)) });
|
|
3826
|
+
};
|
|
3827
|
+
const SpecRenderer = ({
|
|
3828
|
+
spec,
|
|
3829
|
+
definitions,
|
|
3830
|
+
options,
|
|
3831
|
+
sendMessage
|
|
3832
|
+
}) => {
|
|
3833
|
+
const definition = definitions[spec.type];
|
|
3834
|
+
if (!definition) {
|
|
3835
|
+
const error = {
|
|
3836
|
+
type: "unknown_component",
|
|
3837
|
+
message: `Unknown component "${spec.type}"`,
|
|
3838
|
+
raw: JSON.stringify(spec),
|
|
3839
|
+
componentType: spec.type
|
|
3840
|
+
};
|
|
3841
|
+
const custom = options?.onError?.(error);
|
|
3842
|
+
if (custom !== void 0) {
|
|
3843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: custom });
|
|
3844
|
+
}
|
|
3845
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ComponentError, { title: errorTitle(error.type), message: error.message });
|
|
3846
|
+
}
|
|
3847
|
+
const RenderedComponent = definition.component;
|
|
3848
|
+
const children = spec.children?.map((child, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3849
|
+
SpecRenderer,
|
|
3850
|
+
{
|
|
3851
|
+
spec: child,
|
|
3852
|
+
definitions,
|
|
3853
|
+
options,
|
|
3854
|
+
sendMessage
|
|
3855
|
+
},
|
|
3856
|
+
`${child.type}-${index}-${stableKey(child)}`
|
|
3857
|
+
));
|
|
3858
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SpecErrorBoundary, { spec, options, children: /* @__PURE__ */ jsxRuntime.jsx(RenderedComponent, { ...spec.props, sendMessage, children }) });
|
|
3859
|
+
};
|
|
3860
|
+
class SpecErrorBoundary extends React.Component {
|
|
3861
|
+
constructor() {
|
|
3862
|
+
super(...arguments);
|
|
3863
|
+
this.state = { error: null };
|
|
3864
|
+
}
|
|
3865
|
+
static getDerivedStateFromError(error) {
|
|
3866
|
+
return { error };
|
|
3867
|
+
}
|
|
3868
|
+
render() {
|
|
3869
|
+
if (this.state.error) {
|
|
3870
|
+
const { spec, options } = this.props;
|
|
3871
|
+
const catalogError = {
|
|
3872
|
+
type: "render_error",
|
|
3873
|
+
message: `Error rendering "${spec.type}": ${this.state.error.message}`,
|
|
3874
|
+
raw: JSON.stringify(spec),
|
|
3875
|
+
componentType: spec.type
|
|
3876
|
+
};
|
|
3877
|
+
const custom = options?.onError?.(catalogError);
|
|
3878
|
+
if (custom !== void 0) {
|
|
3879
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: custom });
|
|
3880
|
+
}
|
|
3881
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3882
|
+
ComponentError,
|
|
3883
|
+
{
|
|
3884
|
+
title: errorTitle(catalogError.type),
|
|
3885
|
+
message: catalogError.message
|
|
3886
|
+
}
|
|
3887
|
+
);
|
|
3888
|
+
}
|
|
3889
|
+
return this.props.children;
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
function stableKey(spec) {
|
|
3893
|
+
const str = JSON.stringify({
|
|
3894
|
+
t: spec.type,
|
|
3895
|
+
p: spec.props,
|
|
3896
|
+
c: spec.children
|
|
3897
|
+
});
|
|
3898
|
+
let h = 0;
|
|
3899
|
+
for (let i = 0; i < str.length; i++) {
|
|
3900
|
+
h = h * 31 + str.charCodeAt(i) | 0;
|
|
3901
|
+
}
|
|
3902
|
+
return (h >>> 0).toString(36);
|
|
3903
|
+
}
|
|
3904
|
+
function errorTitle(type) {
|
|
3905
|
+
switch (type) {
|
|
3906
|
+
case "unknown_component":
|
|
3907
|
+
return "Unknown Component";
|
|
3908
|
+
case "invalid_props":
|
|
3909
|
+
return "Invalid Props";
|
|
3910
|
+
case "render_error":
|
|
3911
|
+
return "Render Error";
|
|
3912
|
+
default:
|
|
3913
|
+
return "Invalid Component";
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
function getChildText(children) {
|
|
3917
|
+
if (children === null || children === void 0) {
|
|
3918
|
+
return "";
|
|
3919
|
+
}
|
|
3920
|
+
if (typeof children === "string") {
|
|
3921
|
+
return children;
|
|
3922
|
+
}
|
|
3923
|
+
if (typeof children === "number") {
|
|
3924
|
+
return String(children);
|
|
3925
|
+
}
|
|
3926
|
+
if (Array.isArray(children)) {
|
|
3927
|
+
return children.map(getChildText).join("");
|
|
3928
|
+
}
|
|
3929
|
+
if (typeof children === "object") {
|
|
3930
|
+
if ("props" in children && children.props) {
|
|
3931
|
+
const element = children;
|
|
3932
|
+
return getChildText(element.props.children);
|
|
3933
|
+
}
|
|
3934
|
+
}
|
|
3935
|
+
return "";
|
|
3936
|
+
}
|
|
3937
|
+
function createComponentPre(definitions, options) {
|
|
3938
|
+
const language = options?.language ?? "component";
|
|
3939
|
+
const className = `language-${language}`;
|
|
3940
|
+
const ComponentPre = ({ children, ...props }) => {
|
|
3941
|
+
if (children && typeof children === "object" && "props" in children) {
|
|
3942
|
+
const codeElement = children;
|
|
3943
|
+
if (codeElement.props?.className === className) {
|
|
3944
|
+
const codeContent = getChildText(codeElement.props?.children);
|
|
3945
|
+
if (codeContent) {
|
|
3946
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3947
|
+
ComponentRenderer,
|
|
3948
|
+
{
|
|
3949
|
+
raw: codeContent,
|
|
3950
|
+
definitions,
|
|
3951
|
+
options
|
|
3952
|
+
}
|
|
3953
|
+
);
|
|
3954
|
+
}
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
return /* @__PURE__ */ jsxRuntime.jsx("pre", { ...props, children });
|
|
3958
|
+
};
|
|
3959
|
+
ComponentPre.displayName = "ComponentPre";
|
|
3960
|
+
return ComponentPre;
|
|
3961
|
+
}
|
|
3962
|
+
function describeJsonSchemaProperty(prop, indent = "") {
|
|
3963
|
+
const description = prop.description ? ` // ${prop.description}` : "";
|
|
3964
|
+
if (prop.anyOf) {
|
|
3965
|
+
const nonNull = prop.anyOf.filter((s) => !(s.type === "null"));
|
|
3966
|
+
const hasNull = prop.anyOf.some((s) => s.type === "null");
|
|
3967
|
+
if (nonNull.length === 1 && hasNull) {
|
|
3968
|
+
return `${describeJsonSchemaProperty(nonNull[0], indent)} | null${description}`;
|
|
3969
|
+
}
|
|
3970
|
+
const parts = prop.anyOf.map(
|
|
3971
|
+
(s) => describeJsonSchemaProperty(s, indent)
|
|
3972
|
+
);
|
|
3973
|
+
return `${parts.join(" | ")}${description}`;
|
|
3974
|
+
}
|
|
3975
|
+
if (prop.enum) {
|
|
3976
|
+
return `${prop.enum.map((v) => `"${v}"`).join(" | ")}${description}`;
|
|
3977
|
+
}
|
|
3978
|
+
if (prop.type === "array") {
|
|
3979
|
+
const items = prop.items ? describeJsonSchemaProperty(prop.items, indent) : "any";
|
|
3980
|
+
return `${items}[]${description}`;
|
|
3981
|
+
}
|
|
3982
|
+
if (prop.type === "object" && prop.properties) {
|
|
3983
|
+
const required = new Set(prop.required ?? []);
|
|
3984
|
+
const fields = [];
|
|
3985
|
+
for (const [key, value] of Object.entries(prop.properties)) {
|
|
3986
|
+
const opt = required.has(key) ? "" : "?";
|
|
3987
|
+
fields.push(
|
|
3988
|
+
`${indent} ${key}: ${describeJsonSchemaProperty(value, indent + " ")}${opt}`
|
|
3989
|
+
);
|
|
3990
|
+
}
|
|
3991
|
+
return `{
|
|
3992
|
+
${fields.join(",\n")}
|
|
3993
|
+
${indent}}${description}`;
|
|
3994
|
+
}
|
|
3995
|
+
if (prop.type === "string") return `string${description}`;
|
|
3996
|
+
if (prop.type === "number" || prop.type === "integer")
|
|
3997
|
+
return `number${description}`;
|
|
3998
|
+
if (prop.type === "boolean") return `boolean${description}`;
|
|
3999
|
+
if (prop.type === "null") return `null${description}`;
|
|
4000
|
+
return `any${description}`;
|
|
4001
|
+
}
|
|
4002
|
+
function describeProps(schema) {
|
|
4003
|
+
try {
|
|
4004
|
+
const jsonSchema = zod.z.toJSONSchema(schema);
|
|
4005
|
+
if (jsonSchema.type === "object" && jsonSchema.properties) {
|
|
4006
|
+
return describeJsonSchemaProperty(jsonSchema);
|
|
4007
|
+
}
|
|
4008
|
+
return "Record<string, any>";
|
|
4009
|
+
} catch {
|
|
4010
|
+
return "Record<string, any>";
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
function generatePrompt(definitions, language = "component") {
|
|
4014
|
+
const names = Object.keys(definitions);
|
|
4015
|
+
if (names.length === 0) {
|
|
4016
|
+
return "";
|
|
4017
|
+
}
|
|
4018
|
+
const componentDocs = names.map((name) => {
|
|
4019
|
+
const def = definitions[name];
|
|
4020
|
+
const propsDesc = describeProps(def.props);
|
|
4021
|
+
return `- **${name}**: ${def.description}
|
|
4022
|
+
Props: ${propsDesc}`;
|
|
4023
|
+
}).join("\n\n");
|
|
4024
|
+
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:
|
|
4025
|
+
|
|
4026
|
+
\`\`\`${language}
|
|
4027
|
+
{ "type": "ComponentName", "props": { ... } }
|
|
4028
|
+
\`\`\`
|
|
4029
|
+
|
|
4030
|
+
For multiple components, use a JSON array:
|
|
4031
|
+
|
|
4032
|
+
\`\`\`${language}
|
|
4033
|
+
[
|
|
4034
|
+
{ "type": "ComponentA", "props": { ... } },
|
|
4035
|
+
{ "type": "ComponentB", "props": { ... } }
|
|
4036
|
+
]
|
|
4037
|
+
\`\`\`
|
|
4038
|
+
|
|
4039
|
+
For nested/composed layouts, use the "children" field:
|
|
4040
|
+
|
|
4041
|
+
\`\`\`${language}
|
|
4042
|
+
{
|
|
4043
|
+
"type": "Parent",
|
|
4044
|
+
"props": { ... },
|
|
4045
|
+
"children": [
|
|
4046
|
+
{ "type": "Child", "props": { ... } }
|
|
4047
|
+
]
|
|
4048
|
+
}
|
|
4049
|
+
\`\`\`
|
|
4050
|
+
|
|
4051
|
+
Available components:
|
|
4052
|
+
|
|
4053
|
+
${componentDocs}`;
|
|
4054
|
+
}
|
|
4055
|
+
function componentCatalog(definitions, options) {
|
|
4056
|
+
const language = options?.language ?? "component";
|
|
4057
|
+
const plugin = remarkComponent.bind(void 0, {
|
|
4058
|
+
language
|
|
4059
|
+
});
|
|
4060
|
+
const Pre = createComponentPre(definitions, options);
|
|
4061
|
+
return {
|
|
4062
|
+
remarkPlugin: plugin,
|
|
4063
|
+
components: { pre: Pre },
|
|
4064
|
+
systemPrompt: () => generatePrompt(definitions, language),
|
|
4065
|
+
definitions
|
|
4066
|
+
};
|
|
4067
|
+
}
|
|
4068
|
+
function createChartComponentDef() {
|
|
4069
|
+
const chartPropsSchema = zod.z.object({
|
|
4070
|
+
type: zod.z.enum([
|
|
4071
|
+
"bar",
|
|
4072
|
+
"line",
|
|
4073
|
+
"area",
|
|
4074
|
+
"pie",
|
|
4075
|
+
"radialBar",
|
|
4076
|
+
"radialArea",
|
|
4077
|
+
"sparkline"
|
|
4078
|
+
]).describe("Chart type"),
|
|
4079
|
+
data: zod.z.array(zod.z.object({ key: zod.z.string(), data: zod.z.number() })).describe("Array of { key, data } data points"),
|
|
4080
|
+
width: zod.z.number().describe("Chart width in px").optional(),
|
|
4081
|
+
height: zod.z.number().describe("Chart height in px").optional(),
|
|
4082
|
+
title: zod.z.string().describe("Chart title").optional()
|
|
4083
|
+
});
|
|
4084
|
+
return {
|
|
4085
|
+
description: "Renders a chart. Supported types: bar, line, area, pie, radialBar, radialArea, sparkline",
|
|
4086
|
+
props: chartPropsSchema,
|
|
4087
|
+
component: ({
|
|
4088
|
+
children: _children,
|
|
4089
|
+
sendMessage: _sendMessage,
|
|
4090
|
+
...config
|
|
4091
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(ChartRenderer, { config })
|
|
4092
|
+
};
|
|
4093
|
+
}
|
|
3800
4094
|
exports2.AgUiEventType = AgUiEventType;
|
|
3801
4095
|
exports2.AppBar = AppBar;
|
|
3802
|
-
exports2.ChartError = ChartError;
|
|
3803
|
-
exports2.ChartPre = ChartPre;
|
|
3804
4096
|
exports2.ChartRenderer = ChartRenderer;
|
|
3805
4097
|
exports2.Chat = Chat;
|
|
3806
4098
|
exports2.ChatBubble = ChatBubble;
|
|
@@ -3809,6 +4101,8 @@ ${response}` : ""}`);
|
|
|
3809
4101
|
exports2.ChatSuggestion = ChatSuggestion;
|
|
3810
4102
|
exports2.ChatSuggestions = ChatSuggestions;
|
|
3811
4103
|
exports2.CodeHighlighter = CodeHighlighter;
|
|
4104
|
+
exports2.ComponentError = ComponentError;
|
|
4105
|
+
exports2.ComponentRenderer = ComponentRenderer;
|
|
3812
4106
|
exports2.FileInput = FileInput;
|
|
3813
4107
|
exports2.Markdown = Markdown;
|
|
3814
4108
|
exports2.MentionList = MentionList;
|
|
@@ -3837,21 +4131,21 @@ ${response}` : ""}`);
|
|
|
3837
4131
|
exports2.TableDataCell = TableDataCell;
|
|
3838
4132
|
exports2.TableHeaderCell = TableHeaderCell;
|
|
3839
4133
|
exports2.bitcoinMatcher = bitcoinMatcher;
|
|
3840
|
-
exports2.chartComponents = chartComponents;
|
|
3841
4134
|
exports2.chatTheme = chatTheme;
|
|
3842
4135
|
exports2.commonRedactMatchers = commonRedactMatchers;
|
|
4136
|
+
exports2.componentCatalog = componentCatalog;
|
|
4137
|
+
exports2.createChartComponentDef = createChartComponentDef;
|
|
4138
|
+
exports2.createComponentPre = createComponentPre;
|
|
3843
4139
|
exports2.creditCardMatcher = creditCardMatcher;
|
|
3844
4140
|
exports2.dark = dark;
|
|
3845
|
-
exports2.
|
|
3846
|
-
exports2.isChartClassName = isChartClassName;
|
|
4141
|
+
exports2.generatePrompt = generatePrompt;
|
|
3847
4142
|
exports2.light = light;
|
|
3848
|
-
exports2.
|
|
3849
|
-
exports2.remarkChart = remarkChart;
|
|
4143
|
+
exports2.remarkComponent = remarkComponent;
|
|
3850
4144
|
exports2.remarkCve = remarkCve;
|
|
3851
4145
|
exports2.remarkRedact = remarkRedact;
|
|
3852
4146
|
exports2.ssnMatcher = ssnMatcher;
|
|
3853
4147
|
exports2.useAgUi = useAgUi;
|
|
3854
|
-
exports2.
|
|
4148
|
+
exports2.validateSpec = validateSpec;
|
|
3855
4149
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
|
3856
|
-
});
|
|
4150
|
+
}));
|
|
3857
4151
|
//# sourceMappingURL=index.umd.cjs.map
|