veryfront 0.0.71 → 0.0.73

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.
@@ -358,7 +358,7 @@ var ToolInvocation = React5.forwardRef(({ className, name, input, output: _outpu
358
358
  ] }),
359
359
  dynamic && /* @__PURE__ */ jsx5("span", { "data-tool-dynamic": "", children: "[dynamic]" })
360
360
  ] }),
361
- input && /* @__PURE__ */ jsx5("div", { "data-tool-input": "", children: /* @__PURE__ */ jsx5("pre", { children: JSON.stringify(input, null, 2) }) }),
361
+ input !== void 0 && /* @__PURE__ */ jsx5("div", { "data-tool-input": "", children: /* @__PURE__ */ jsx5("pre", { children: JSON.stringify(input, null, 2) }) }),
362
362
  errorText && /* @__PURE__ */ jsx5("div", { "data-tool-error": "", children: errorText }),
363
363
  children
364
364
  ]
@@ -382,6 +382,9 @@ var ToolResult = React5.forwardRef(
382
382
  }
383
383
  );
384
384
  ToolResult.displayName = "ToolResult";
385
+ function isDynamicTool(tool) {
386
+ return tool.type === "dynamic-tool";
387
+ }
385
388
  var ToolList = React5.forwardRef(
386
389
  ({ className, tools, renderTool, ...props }, ref) => {
387
390
  return /* @__PURE__ */ jsx5(
@@ -399,7 +402,7 @@ var ToolList = React5.forwardRef(
399
402
  input: tool.input,
400
403
  state: tool.state,
401
404
  errorText: tool.errorText,
402
- dynamic: tool.type === "dynamic-tool",
405
+ dynamic: isDynamicTool(tool),
403
406
  children: tool.output !== void 0 && /* @__PURE__ */ jsx5(ToolResult, { output: tool.output })
404
407
  },
405
408
  tool.toolCallId
@@ -732,14 +735,497 @@ function Markdown({
732
735
  }
733
736
 
734
737
  // src/ai/react/components/chat.tsx
735
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
738
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
739
+ function CircleIcon({ className }) {
740
+ return /* @__PURE__ */ jsx7(
741
+ "svg",
742
+ {
743
+ className: cn("size-4", className),
744
+ viewBox: "0 0 24 24",
745
+ fill: "none",
746
+ stroke: "currentColor",
747
+ strokeWidth: "2",
748
+ strokeLinecap: "round",
749
+ strokeLinejoin: "round",
750
+ children: /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10" })
751
+ }
752
+ );
753
+ }
754
+ function ClockIcon({ className }) {
755
+ return /* @__PURE__ */ jsxs4(
756
+ "svg",
757
+ {
758
+ className: cn("size-4", className),
759
+ viewBox: "0 0 24 24",
760
+ fill: "none",
761
+ stroke: "currentColor",
762
+ strokeWidth: "2",
763
+ strokeLinecap: "round",
764
+ strokeLinejoin: "round",
765
+ children: [
766
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10" }),
767
+ /* @__PURE__ */ jsx7("polyline", { points: "12 6 12 12 16 14" })
768
+ ]
769
+ }
770
+ );
771
+ }
772
+ function CheckCircleIcon({ className }) {
773
+ return /* @__PURE__ */ jsxs4(
774
+ "svg",
775
+ {
776
+ className: cn("size-4", className),
777
+ viewBox: "0 0 24 24",
778
+ fill: "none",
779
+ stroke: "currentColor",
780
+ strokeWidth: "2",
781
+ strokeLinecap: "round",
782
+ strokeLinejoin: "round",
783
+ children: [
784
+ /* @__PURE__ */ jsx7("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
785
+ /* @__PURE__ */ jsx7("polyline", { points: "22 4 12 14.01 9 11.01" })
786
+ ]
787
+ }
788
+ );
789
+ }
790
+ function XCircleIcon({ className }) {
791
+ return /* @__PURE__ */ jsxs4(
792
+ "svg",
793
+ {
794
+ className: cn("size-4", className),
795
+ viewBox: "0 0 24 24",
796
+ fill: "none",
797
+ stroke: "currentColor",
798
+ strokeWidth: "2",
799
+ strokeLinecap: "round",
800
+ strokeLinejoin: "round",
801
+ children: [
802
+ /* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "10" }),
803
+ /* @__PURE__ */ jsx7("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
804
+ /* @__PURE__ */ jsx7("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
805
+ ]
806
+ }
807
+ );
808
+ }
809
+ function WrenchIcon({ className }) {
810
+ return /* @__PURE__ */ jsx7(
811
+ "svg",
812
+ {
813
+ className: cn("size-4", className),
814
+ viewBox: "0 0 24 24",
815
+ fill: "none",
816
+ stroke: "currentColor",
817
+ strokeWidth: "2",
818
+ strokeLinecap: "round",
819
+ strokeLinejoin: "round",
820
+ children: /* @__PURE__ */ jsx7("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" })
821
+ }
822
+ );
823
+ }
824
+ function ChevronDownIcon({ className }) {
825
+ return /* @__PURE__ */ jsx7(
826
+ "svg",
827
+ {
828
+ className: cn("size-4", className),
829
+ viewBox: "0 0 24 24",
830
+ fill: "none",
831
+ stroke: "currentColor",
832
+ strokeWidth: "2",
833
+ strokeLinecap: "round",
834
+ strokeLinejoin: "round",
835
+ children: /* @__PURE__ */ jsx7("polyline", { points: "6 9 12 15 18 9" })
836
+ }
837
+ );
838
+ }
839
+ function BrainIcon({ className }) {
840
+ return /* @__PURE__ */ jsxs4(
841
+ "svg",
842
+ {
843
+ className: cn("size-4", className),
844
+ viewBox: "0 0 24 24",
845
+ fill: "none",
846
+ stroke: "currentColor",
847
+ strokeWidth: "2",
848
+ strokeLinecap: "round",
849
+ strokeLinejoin: "round",
850
+ children: [
851
+ /* @__PURE__ */ jsx7("path", { d: "M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z" }),
852
+ /* @__PURE__ */ jsx7("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.526 5.77 4 4 0 0 1-.556 6.588A4 4 0 1 1 12 18Z" }),
853
+ /* @__PURE__ */ jsx7("path", { d: "M15 13a4.5 4.5 0 0 1-3-4 4.5 4.5 0 0 1-3 4" }),
854
+ /* @__PURE__ */ jsx7("path", { d: "M17.599 6.5a3 3 0 0 0 .399-1.375" }),
855
+ /* @__PURE__ */ jsx7("path", { d: "M6.003 5.125A3 3 0 0 0 6.401 6.5" }),
856
+ /* @__PURE__ */ jsx7("path", { d: "M3.477 10.896a4 4 0 0 1 .585-.396" }),
857
+ /* @__PURE__ */ jsx7("path", { d: "M19.938 10.5a4 4 0 0 1 .585.396" }),
858
+ /* @__PURE__ */ jsx7("path", { d: "M6 18a4 4 0 0 1-1.967-.516" }),
859
+ /* @__PURE__ */ jsx7("path", { d: "M19.967 17.484A4 4 0 0 1 18 18" })
860
+ ]
861
+ }
862
+ );
863
+ }
864
+ function MessageSquareIcon({ className }) {
865
+ return /* @__PURE__ */ jsx7(
866
+ "svg",
867
+ {
868
+ className: cn("size-4", className),
869
+ viewBox: "0 0 24 24",
870
+ fill: "none",
871
+ stroke: "currentColor",
872
+ strokeWidth: "2",
873
+ strokeLinecap: "round",
874
+ strokeLinejoin: "round",
875
+ children: /* @__PURE__ */ jsx7("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
876
+ }
877
+ );
878
+ }
879
+ function ArrowDownIcon({ className }) {
880
+ return /* @__PURE__ */ jsxs4(
881
+ "svg",
882
+ {
883
+ className: cn("size-4", className),
884
+ viewBox: "0 0 24 24",
885
+ fill: "none",
886
+ stroke: "currentColor",
887
+ strokeWidth: "2",
888
+ strokeLinecap: "round",
889
+ strokeLinejoin: "round",
890
+ children: [
891
+ /* @__PURE__ */ jsx7("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
892
+ /* @__PURE__ */ jsx7("polyline", { points: "19 12 12 19 5 12" })
893
+ ]
894
+ }
895
+ );
896
+ }
897
+ function RefreshCwIcon({ className }) {
898
+ return /* @__PURE__ */ jsxs4(
899
+ "svg",
900
+ {
901
+ className: cn("size-4", className),
902
+ viewBox: "0 0 24 24",
903
+ fill: "none",
904
+ stroke: "currentColor",
905
+ strokeWidth: "2",
906
+ strokeLinecap: "round",
907
+ strokeLinejoin: "round",
908
+ children: [
909
+ /* @__PURE__ */ jsx7("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
910
+ /* @__PURE__ */ jsx7("path", { d: "M21 3v5h-5" }),
911
+ /* @__PURE__ */ jsx7("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
912
+ /* @__PURE__ */ jsx7("path", { d: "M8 16H3v5" })
913
+ ]
914
+ }
915
+ );
916
+ }
917
+ function CopyIcon({ className }) {
918
+ return /* @__PURE__ */ jsxs4(
919
+ "svg",
920
+ {
921
+ className: cn("size-4", className),
922
+ viewBox: "0 0 24 24",
923
+ fill: "none",
924
+ stroke: "currentColor",
925
+ strokeWidth: "2",
926
+ strokeLinecap: "round",
927
+ strokeLinejoin: "round",
928
+ children: [
929
+ /* @__PURE__ */ jsx7("rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2" }),
930
+ /* @__PURE__ */ jsx7("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })
931
+ ]
932
+ }
933
+ );
934
+ }
935
+ function CheckIcon({ className }) {
936
+ return /* @__PURE__ */ jsx7(
937
+ "svg",
938
+ {
939
+ className: cn("size-4", className),
940
+ viewBox: "0 0 24 24",
941
+ fill: "none",
942
+ stroke: "currentColor",
943
+ strokeWidth: "2",
944
+ strokeLinecap: "round",
945
+ strokeLinejoin: "round",
946
+ children: /* @__PURE__ */ jsx7("polyline", { points: "20 6 9 17 4 12" })
947
+ }
948
+ );
949
+ }
950
+ function Shimmer({ children }) {
951
+ return /* @__PURE__ */ jsx7("span", { className: "relative inline-block overflow-hidden", children: /* @__PURE__ */ jsx7("span", { className: "animate-pulse", children }) });
952
+ }
953
+ function ReasoningCard({ text, isStreaming = false }) {
954
+ const [isOpen, setIsOpen] = React8.useState(true);
955
+ React8.useEffect(() => {
956
+ if (!isStreaming && isOpen) {
957
+ const timer = setTimeout(() => {
958
+ setIsOpen(false);
959
+ }, 1e3);
960
+ return () => clearTimeout(timer);
961
+ }
962
+ }, [isStreaming, isOpen]);
963
+ return /* @__PURE__ */ jsxs4("div", { className: "not-prose mb-4", children: [
964
+ /* @__PURE__ */ jsxs4(
965
+ "button",
966
+ {
967
+ type: "button",
968
+ onClick: () => setIsOpen(!isOpen),
969
+ className: "flex w-full items-center gap-2 text-muted-foreground text-sm transition-colors hover:text-foreground",
970
+ children: [
971
+ /* @__PURE__ */ jsx7(BrainIcon, { className: "size-4" }),
972
+ isStreaming ? /* @__PURE__ */ jsx7(Shimmer, { children: "Thinking..." }) : /* @__PURE__ */ jsx7("span", { children: "Thought process" }),
973
+ /* @__PURE__ */ jsx7(
974
+ ChevronDownIcon,
975
+ {
976
+ className: cn(
977
+ "size-4 transition-transform",
978
+ isOpen && "rotate-180"
979
+ )
980
+ }
981
+ )
982
+ ]
983
+ }
984
+ ),
985
+ isOpen && /* @__PURE__ */ jsx7("div", { className: "mt-4 text-sm text-muted-foreground border-l-2 border-muted pl-4 ml-2", children: /* @__PURE__ */ jsx7(Markdown, { className: "text-sm", children: text }) })
986
+ ] });
987
+ }
988
+ function Suggestion({ suggestion, onClick, className, icon }) {
989
+ return /* @__PURE__ */ jsxs4(
990
+ "button",
991
+ {
992
+ type: "button",
993
+ onClick: () => onClick?.(suggestion),
994
+ className: cn(
995
+ "group flex items-start gap-3 rounded-xl border border-border bg-background p-4 text-left text-sm text-foreground transition-all hover:bg-muted hover:border-muted-foreground/20",
996
+ className
997
+ ),
998
+ children: [
999
+ icon && /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-muted-foreground group-hover:text-foreground transition-colors", children: icon }),
1000
+ /* @__PURE__ */ jsx7("span", { className: "line-clamp-2", children: suggestion })
1001
+ ]
1002
+ }
1003
+ );
1004
+ }
1005
+ function Suggestions({ children, className, layout = "grid" }) {
1006
+ if (layout === "horizontal") {
1007
+ return /* @__PURE__ */ jsx7("div", { className: cn("flex gap-2 overflow-x-auto pb-2 scrollbar-hide", className), children });
1008
+ }
1009
+ return /* @__PURE__ */ jsx7("div", { className: cn("grid grid-cols-2 gap-3 max-w-2xl mx-auto", className), children });
1010
+ }
1011
+ function ConversationEmptyState({
1012
+ icon,
1013
+ title = "What can I help with?",
1014
+ description,
1015
+ children,
1016
+ className
1017
+ }) {
1018
+ return /* @__PURE__ */ jsxs4("div", { className: cn("flex flex-col items-center justify-center text-center", className), children: [
1019
+ icon && /* @__PURE__ */ jsx7("div", { className: "mb-4 text-muted-foreground", children: icon }),
1020
+ /* @__PURE__ */ jsx7("h1", { className: "text-3xl font-semibold text-foreground", children: title }),
1021
+ description && /* @__PURE__ */ jsx7("p", { className: "mt-2 text-base text-muted-foreground max-w-md", children: description }),
1022
+ children
1023
+ ] });
1024
+ }
1025
+ function ConversationScrollButton({
1026
+ onClick,
1027
+ visible = true,
1028
+ className
1029
+ }) {
1030
+ if (!visible)
1031
+ return null;
1032
+ return /* @__PURE__ */ jsx7(
1033
+ "button",
1034
+ {
1035
+ type: "button",
1036
+ onClick,
1037
+ className: cn(
1038
+ "absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full border border-border bg-background p-2 shadow-lg transition-all hover:bg-muted",
1039
+ className
1040
+ ),
1041
+ children: /* @__PURE__ */ jsx7(ArrowDownIcon, { className: "size-4" })
1042
+ }
1043
+ );
1044
+ }
1045
+ function MessageActions({ content, className }) {
1046
+ const [copied, setCopied] = React8.useState(false);
1047
+ const handleCopy = async () => {
1048
+ try {
1049
+ await navigator.clipboard.writeText(content);
1050
+ setCopied(true);
1051
+ setTimeout(() => setCopied(false), 2e3);
1052
+ } catch {
1053
+ const textarea = document.createElement("textarea");
1054
+ textarea.value = content;
1055
+ document.body.appendChild(textarea);
1056
+ textarea.select();
1057
+ document.execCommand("copy");
1058
+ document.body.removeChild(textarea);
1059
+ setCopied(true);
1060
+ setTimeout(() => setCopied(false), 2e3);
1061
+ }
1062
+ };
1063
+ return /* @__PURE__ */ jsx7("div", { className: cn("flex items-center gap-1 mt-2", className), children: /* @__PURE__ */ jsx7(
1064
+ "button",
1065
+ {
1066
+ type: "button",
1067
+ onClick: handleCopy,
1068
+ className: "inline-flex items-center gap-1 px-2 py-1 text-xs text-muted-foreground hover:text-foreground hover:bg-muted rounded transition-colors",
1069
+ title: copied ? "Copied!" : "Copy to clipboard",
1070
+ children: copied ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
1071
+ /* @__PURE__ */ jsx7(CheckIcon, { className: "size-3" }),
1072
+ /* @__PURE__ */ jsx7("span", { children: "Copied" })
1073
+ ] }) : /* @__PURE__ */ jsxs4(Fragment4, { children: [
1074
+ /* @__PURE__ */ jsx7(CopyIcon, { className: "size-3" }),
1075
+ /* @__PURE__ */ jsx7("span", { children: "Copy" })
1076
+ ] })
1077
+ }
1078
+ ) });
1079
+ }
1080
+ function ToolStatusBadge({ state }) {
1081
+ const labels = {
1082
+ "input-streaming": "Pending",
1083
+ "input-available": "Running",
1084
+ "approval-requested": "Awaiting Approval",
1085
+ "approval-responded": "Responded",
1086
+ "output-available": "Completed",
1087
+ "output-error": "Error",
1088
+ "output-denied": "Denied",
1089
+ // Legacy states
1090
+ "call": "Running",
1091
+ "partial-call": "Running",
1092
+ "result": "Completed",
1093
+ "error": "Error"
1094
+ };
1095
+ const icons = {
1096
+ "input-streaming": /* @__PURE__ */ jsx7(CircleIcon, { className: "size-3.5" }),
1097
+ "input-available": /* @__PURE__ */ jsx7(ClockIcon, { className: "size-3.5 animate-pulse" }),
1098
+ "approval-requested": /* @__PURE__ */ jsx7(ClockIcon, { className: "size-3.5 text-yellow-600" }),
1099
+ "approval-responded": /* @__PURE__ */ jsx7(CheckCircleIcon, { className: "size-3.5 text-blue-600" }),
1100
+ "output-available": /* @__PURE__ */ jsx7(CheckCircleIcon, { className: "size-3.5 text-green-600" }),
1101
+ "output-error": /* @__PURE__ */ jsx7(XCircleIcon, { className: "size-3.5 text-red-600" }),
1102
+ "output-denied": /* @__PURE__ */ jsx7(XCircleIcon, { className: "size-3.5 text-orange-600" }),
1103
+ // Legacy states
1104
+ "call": /* @__PURE__ */ jsx7(ClockIcon, { className: "size-3.5 animate-pulse" }),
1105
+ "partial-call": /* @__PURE__ */ jsx7(ClockIcon, { className: "size-3.5 animate-pulse" }),
1106
+ "result": /* @__PURE__ */ jsx7(CheckCircleIcon, { className: "size-3.5 text-green-600" }),
1107
+ "error": /* @__PURE__ */ jsx7(XCircleIcon, { className: "size-3.5 text-red-600" })
1108
+ };
1109
+ return /* @__PURE__ */ jsxs4("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-secondary px-2.5 py-0.5 text-xs font-medium text-secondary-foreground border border-border", children: [
1110
+ icons[state] || /* @__PURE__ */ jsx7(CircleIcon, { className: "size-3.5" }),
1111
+ labels[state] || state
1112
+ ] });
1113
+ }
1114
+ function formatJsonWithHighlight(obj) {
1115
+ if (obj === void 0 || obj === null)
1116
+ return null;
1117
+ const jsonStr = typeof obj === "string" ? obj : JSON.stringify(obj, null, 2);
1118
+ const highlighted = jsonStr.replace(/"([^"]+)":/g, '<span class="text-green-600 dark:text-green-400">"$1"</span>:').replace(/: "([^"]*)"/g, ': <span class="text-amber-600 dark:text-amber-400">"$1"</span>').replace(/: (\d+)/g, ': <span class="text-blue-600 dark:text-blue-400">$1</span>').replace(/: (true|false)/g, ': <span class="text-purple-600 dark:text-purple-400">$1</span>');
1119
+ return /* @__PURE__ */ jsx7(
1120
+ "pre",
1121
+ {
1122
+ className: "text-sm font-mono whitespace-pre-wrap",
1123
+ dangerouslySetInnerHTML: { __html: highlighted }
1124
+ }
1125
+ );
1126
+ }
1127
+ function renderOutputAsTable(output) {
1128
+ if (!Array.isArray(output) || output.length === 0)
1129
+ return null;
1130
+ const firstItem = output[0];
1131
+ if (typeof firstItem !== "object" || firstItem === null)
1132
+ return null;
1133
+ const keys = Object.keys(firstItem);
1134
+ if (keys.length === 0)
1135
+ return null;
1136
+ return /* @__PURE__ */ jsx7("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs4("table", { className: "min-w-full text-sm", children: [
1137
+ /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsx7("tr", { className: "border-b border-neutral-200 dark:border-neutral-700", children: keys.map((key) => /* @__PURE__ */ jsx7(
1138
+ "th",
1139
+ {
1140
+ className: "px-4 py-2 text-left font-semibold text-neutral-900 dark:text-neutral-100",
1141
+ children: key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase())
1142
+ },
1143
+ key
1144
+ )) }) }),
1145
+ /* @__PURE__ */ jsx7("tbody", { children: output.map((row, i) => /* @__PURE__ */ jsx7("tr", { className: "border-b border-neutral-100 dark:border-neutral-800", children: keys.map((key) => /* @__PURE__ */ jsx7("td", { className: "px-4 py-2 text-neutral-700 dark:text-neutral-300", children: String(row[key] ?? "") }, key)) }, i)) })
1146
+ ] }) });
1147
+ }
1148
+ function ToolCallCard({ tool }) {
1149
+ const [isExpanded, setIsExpanded] = React8.useState(true);
1150
+ const tableOutput = tool.output !== void 0 ? renderOutputAsTable(tool.output) : null;
1151
+ return /* @__PURE__ */ jsxs4("div", { className: "not-prose w-full rounded-md border border-border bg-card", children: [
1152
+ /* @__PURE__ */ jsxs4(
1153
+ "button",
1154
+ {
1155
+ type: "button",
1156
+ onClick: () => setIsExpanded(!isExpanded),
1157
+ className: "group flex w-full items-center justify-between gap-4 p-3 hover:bg-muted/50 transition-colors",
1158
+ children: [
1159
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
1160
+ /* @__PURE__ */ jsx7(WrenchIcon, { className: "size-4 text-muted-foreground" }),
1161
+ /* @__PURE__ */ jsx7("span", { className: "font-medium text-sm text-foreground", children: tool.toolName }),
1162
+ /* @__PURE__ */ jsx7(ToolStatusBadge, { state: tool.state })
1163
+ ] }),
1164
+ /* @__PURE__ */ jsx7(
1165
+ ChevronDownIcon,
1166
+ {
1167
+ className: cn(
1168
+ "size-4 text-muted-foreground transition-transform",
1169
+ isExpanded && "rotate-180"
1170
+ )
1171
+ }
1172
+ )
1173
+ ]
1174
+ }
1175
+ ),
1176
+ isExpanded && /* @__PURE__ */ jsxs4("div", { className: "border-t border-border", children: [
1177
+ tool.input !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "space-y-2 overflow-hidden p-4", children: [
1178
+ /* @__PURE__ */ jsx7("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Parameters" }),
1179
+ /* @__PURE__ */ jsx7("div", { className: "rounded-md bg-muted/50 p-3", children: formatJsonWithHighlight(tool.input) })
1180
+ ] }),
1181
+ tool.output !== void 0 && /* @__PURE__ */ jsxs4("div", { className: "space-y-2 p-4 border-t border-border", children: [
1182
+ /* @__PURE__ */ jsx7("h4", { className: "font-medium text-muted-foreground text-xs uppercase tracking-wide", children: "Result" }),
1183
+ /* @__PURE__ */ jsx7("div", { className: "overflow-x-auto rounded-md bg-muted/50 text-foreground", children: tableOutput || /* @__PURE__ */ jsx7("div", { className: "p-3", children: formatJsonWithHighlight(tool.output) }) })
1184
+ ] }),
1185
+ tool.errorText && /* @__PURE__ */ jsxs4("div", { className: "space-y-2 p-4 border-t border-border", children: [
1186
+ /* @__PURE__ */ jsx7("h4", { className: "font-medium text-destructive text-xs uppercase tracking-wide", children: "Error" }),
1187
+ /* @__PURE__ */ jsx7("div", { className: "rounded-md bg-destructive/10 text-destructive p-3 text-sm", children: tool.errorText })
1188
+ ] })
1189
+ ] })
1190
+ ] });
1191
+ }
736
1192
  function getTextContent(message) {
737
1193
  return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
738
1194
  }
739
- function getToolParts(message) {
740
- return message.parts.filter(
741
- (p) => p.type === "tool-call" || p.type === "dynamic-tool"
742
- );
1195
+ function isToolPart(part) {
1196
+ return part.type.startsWith("tool-") && part.type !== "tool-result" || part.type === "dynamic-tool";
1197
+ }
1198
+ function isReasoningPart(part) {
1199
+ return part.type === "reasoning";
1200
+ }
1201
+ function groupPartsInOrder(parts) {
1202
+ const groups = [];
1203
+ let currentTextGroup = [];
1204
+ for (const part of parts) {
1205
+ if (part.type === "text") {
1206
+ currentTextGroup.push(part.text);
1207
+ } else if (isToolPart(part)) {
1208
+ if (currentTextGroup.length > 0) {
1209
+ groups.push({ type: "text", content: currentTextGroup.join("") });
1210
+ currentTextGroup = [];
1211
+ }
1212
+ groups.push({ type: "tool", tool: part });
1213
+ } else if (isReasoningPart(part)) {
1214
+ if (currentTextGroup.length > 0) {
1215
+ groups.push({ type: "text", content: currentTextGroup.join("") });
1216
+ currentTextGroup = [];
1217
+ }
1218
+ groups.push({
1219
+ type: "reasoning",
1220
+ text: part.text,
1221
+ isStreaming: part.state === "streaming"
1222
+ });
1223
+ }
1224
+ }
1225
+ if (currentTextGroup.length > 0) {
1226
+ groups.push({ type: "text", content: currentTextGroup.join("") });
1227
+ }
1228
+ return groups;
743
1229
  }
744
1230
  var Chat = React8.forwardRef(
745
1231
  ({
@@ -750,6 +1236,7 @@ var Chat = React8.forwardRef(
750
1236
  onSubmit,
751
1237
  handleSubmit,
752
1238
  stop,
1239
+ reload,
753
1240
  enableVoice = false,
754
1241
  onVoice,
755
1242
  setInput,
@@ -761,7 +1248,12 @@ var Chat = React8.forwardRef(
761
1248
  theme: userTheme,
762
1249
  renderMessage,
763
1250
  renderTool,
764
- multiline = false
1251
+ multiline = false,
1252
+ suggestions,
1253
+ onSuggestionClick,
1254
+ emptyState,
1255
+ showScrollButton = false,
1256
+ showMessageActions = true
765
1257
  }, ref) => {
766
1258
  const theme = mergeThemes(defaultChatTheme, userTheme);
767
1259
  const messagesEndRef = React8.useRef(null);
@@ -793,54 +1285,106 @@ var Chat = React8.forwardRef(
793
1285
  className: cn(theme.container, className),
794
1286
  style: { maxHeight },
795
1287
  children: [
796
- /* @__PURE__ */ jsx7(MessageList, { className: "flex-1 min-h-0 overflow-y-auto", children: /* @__PURE__ */ jsxs4("div", { className: "max-w-2xl mx-auto px-4 py-4 space-y-2", children: [
797
- messages.map((msg) => {
798
- const content = getTextContent(msg);
799
- const toolParts = getToolParts(msg);
800
- return renderMessage ? /* @__PURE__ */ jsx7(React8.Fragment, { children: renderMessage(msg) }, msg.id) : /* @__PURE__ */ jsx7(
801
- MessageItem,
1288
+ /* @__PURE__ */ jsxs4(MessageList, { className: "flex-1 min-h-0 overflow-y-auto relative", children: [
1289
+ messages.length === 0 ? /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center h-full px-4", children: [
1290
+ /* @__PURE__ */ jsx7("div", { className: "flex-1" }),
1291
+ /* @__PURE__ */ jsx7(
1292
+ ConversationEmptyState,
802
1293
  {
803
- role: msg.role,
804
- className: cn(
805
- "flex",
806
- msg.role === "user" ? "justify-end" : "justify-start"
807
- ),
808
- children: /* @__PURE__ */ jsxs4("div", { className: theme.message?.[msg.role] || theme.message?.assistant, children: [
809
- msg.role === "user" ? /* @__PURE__ */ jsx7("p", { className: "whitespace-pre-wrap text-[15px] leading-relaxed", children: content }) : /* @__PURE__ */ jsx7(Markdown, { className: "text-[15px] leading-relaxed", children: content }),
810
- toolParts.length > 0 && /* @__PURE__ */ jsx7("div", { className: "mt-2 space-y-1", children: toolParts.map(
811
- (tool) => renderTool ? /* @__PURE__ */ jsx7(React8.Fragment, { children: renderTool(tool) }, tool.toolCallId) : /* @__PURE__ */ jsxs4(
812
- "div",
813
- {
814
- className: cn(
815
- "text-xs rounded px-2 py-1",
816
- tool.type === "dynamic-tool" ? "bg-blue-50 dark:bg-blue-900/20" : "bg-neutral-100 dark:bg-neutral-800"
817
- ),
818
- children: [
819
- /* @__PURE__ */ jsx7("span", { className: "font-mono", children: tool.toolName }),
820
- /* @__PURE__ */ jsxs4("span", { className: "ml-2 opacity-70", children: [
821
- "[",
822
- tool.state,
823
- "]"
824
- ] }),
825
- tool.errorText && /* @__PURE__ */ jsx7("div", { className: "text-red-600 dark:text-red-400 mt-1", children: tool.errorText })
826
- ]
827
- },
828
- tool.toolCallId
829
- )
830
- ) })
831
- ] })
1294
+ icon: emptyState?.icon || /* @__PURE__ */ jsx7(MessageSquareIcon, { className: "size-10" }),
1295
+ title: emptyState?.title || "What can I help with?",
1296
+ description: emptyState?.description
1297
+ }
1298
+ ),
1299
+ suggestions && suggestions.length > 0 && /* @__PURE__ */ jsx7("div", { className: "w-full max-w-2xl mt-6 mb-8", children: /* @__PURE__ */ jsx7(Suggestions, { layout: "grid", children: suggestions.map((suggestion) => /* @__PURE__ */ jsx7(
1300
+ Suggestion,
1301
+ {
1302
+ suggestion,
1303
+ onClick: onSuggestionClick
832
1304
  },
833
- msg.id
834
- );
835
- }),
836
- isLoading && /* @__PURE__ */ jsx7("div", { className: "flex justify-start", children: /* @__PURE__ */ jsx7("div", { className: "bg-neutral-100 dark:bg-neutral-800 rounded-[20px] rounded-bl-[4px] px-4 py-3", children: /* @__PURE__ */ jsxs4("div", { className: "flex gap-1.5 items-center", children: [
837
- /* @__PURE__ */ jsx7("span", { className: cn(theme.loading) }),
838
- /* @__PURE__ */ jsx7("span", { className: cn(theme.loading), style: { animationDelay: "0.15s" } }),
839
- /* @__PURE__ */ jsx7("span", { className: cn(theme.loading), style: { animationDelay: "0.3s" } })
840
- ] }) }) }),
841
- /* @__PURE__ */ jsx7("div", { ref: messagesEndRef })
842
- ] }) }),
843
- error && /* @__PURE__ */ jsx7("div", { className: "mx-4 mb-2 px-4 py-3 bg-red-50 dark:bg-red-900/20 rounded-2xl text-red-600 dark:text-red-400 text-sm", children: error.message }),
1305
+ suggestion
1306
+ )) }) }),
1307
+ /* @__PURE__ */ jsx7("div", { className: "flex-1" })
1308
+ ] }) : /* @__PURE__ */ jsxs4("div", { className: "max-w-2xl mx-auto px-4 py-4 space-y-2", children: [
1309
+ messages.map((msg) => {
1310
+ if (msg.role === "user") {
1311
+ const content = getTextContent(msg);
1312
+ return renderMessage ? /* @__PURE__ */ jsx7(React8.Fragment, { children: renderMessage(msg) }, msg.id) : /* @__PURE__ */ jsx7(
1313
+ MessageItem,
1314
+ {
1315
+ role: msg.role,
1316
+ className: cn("flex", "justify-end"),
1317
+ children: /* @__PURE__ */ jsx7("div", { className: theme.message?.[msg.role] || theme.message?.user, children: /* @__PURE__ */ jsx7("p", { className: "whitespace-pre-wrap text-[15px] leading-relaxed", children: content }) })
1318
+ },
1319
+ msg.id
1320
+ );
1321
+ }
1322
+ const partGroups = groupPartsInOrder(msg.parts);
1323
+ const textContent = getTextContent(msg);
1324
+ return renderMessage ? /* @__PURE__ */ jsx7(React8.Fragment, { children: renderMessage(msg) }, msg.id) : /* @__PURE__ */ jsx7(
1325
+ MessageItem,
1326
+ {
1327
+ role: msg.role,
1328
+ className: cn("flex", "justify-start"),
1329
+ children: /* @__PURE__ */ jsxs4("div", { className: theme.message?.[msg.role] || theme.message?.assistant, children: [
1330
+ partGroups.map((group, index) => {
1331
+ if (group.type === "text") {
1332
+ return /* @__PURE__ */ jsx7(
1333
+ Markdown,
1334
+ {
1335
+ className: "text-[15px] leading-relaxed",
1336
+ children: group.content
1337
+ },
1338
+ `text-${index}`
1339
+ );
1340
+ }
1341
+ if (group.type === "reasoning") {
1342
+ return /* @__PURE__ */ jsx7(
1343
+ ReasoningCard,
1344
+ {
1345
+ text: group.text,
1346
+ isStreaming: group.isStreaming
1347
+ },
1348
+ `reasoning-${index}`
1349
+ );
1350
+ }
1351
+ return /* @__PURE__ */ jsx7("div", { className: "my-3", children: renderTool ? renderTool(group.tool) : /* @__PURE__ */ jsx7(ToolCallCard, { tool: group.tool }) }, group.tool.toolCallId);
1352
+ }),
1353
+ showMessageActions && textContent && /* @__PURE__ */ jsx7(MessageActions, { content: textContent })
1354
+ ] })
1355
+ },
1356
+ msg.id
1357
+ );
1358
+ }),
1359
+ isLoading && /* @__PURE__ */ jsx7("div", { className: "flex justify-start", children: /* @__PURE__ */ jsx7("div", { className: "bg-neutral-100 dark:bg-neutral-800 rounded-[20px] rounded-bl-[4px] px-4 py-3", children: /* @__PURE__ */ jsxs4("div", { className: "flex gap-1.5 items-center", children: [
1360
+ /* @__PURE__ */ jsx7("span", { className: cn(theme.loading) }),
1361
+ /* @__PURE__ */ jsx7("span", { className: cn(theme.loading), style: { animationDelay: "0.15s" } }),
1362
+ /* @__PURE__ */ jsx7("span", { className: cn(theme.loading), style: { animationDelay: "0.3s" } })
1363
+ ] }) }) }),
1364
+ /* @__PURE__ */ jsx7("div", { ref: messagesEndRef })
1365
+ ] }),
1366
+ showScrollButton && /* @__PURE__ */ jsx7(
1367
+ ConversationScrollButton,
1368
+ {
1369
+ onClick: () => messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
1370
+ }
1371
+ )
1372
+ ] }),
1373
+ error && /* @__PURE__ */ jsxs4("div", { className: "mx-4 mb-2 px-4 py-3 bg-red-50 dark:bg-red-900/20 rounded-2xl text-red-600 dark:text-red-400 text-sm flex items-center justify-between gap-3", children: [
1374
+ /* @__PURE__ */ jsx7("span", { children: error.message }),
1375
+ reload && /* @__PURE__ */ jsxs4(
1376
+ "button",
1377
+ {
1378
+ type: "button",
1379
+ onClick: reload,
1380
+ className: "inline-flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-red-600 dark:text-red-400 bg-red-100 dark:bg-red-900/40 hover:bg-red-200 dark:hover:bg-red-900/60 rounded-lg transition-colors",
1381
+ children: [
1382
+ /* @__PURE__ */ jsx7(RefreshCwIcon, { className: "size-3.5" }),
1383
+ "Retry"
1384
+ ]
1385
+ }
1386
+ )
1387
+ ] }),
844
1388
  /* @__PURE__ */ jsx7("div", { className: "flex-shrink-0 bg-white dark:bg-neutral-900 border-t border-neutral-200 dark:border-neutral-800", children: /* @__PURE__ */ jsx7(
845
1389
  "form",
846
1390
  {
@@ -1063,19 +1607,6 @@ var Message = React10.forwardRef(
1063
1607
  return /* @__PURE__ */ jsx9(React10.Fragment, { children: renderReasoning(part) }, key);
1064
1608
  }
1065
1609
  return /* @__PURE__ */ jsx9("div", { className: "text-sm italic opacity-70 my-2 pl-2 border-l-2", children: part.text }, key);
1066
- case "tool-call":
1067
- if (renderToolCall) {
1068
- return /* @__PURE__ */ jsx9(React10.Fragment, { children: renderToolCall(part) }, key);
1069
- }
1070
- return /* @__PURE__ */ jsxs6("div", { className: "text-xs bg-gray-100 rounded p-2 my-2", children: [
1071
- /* @__PURE__ */ jsx9("span", { className: "font-mono", children: part.toolName }),
1072
- /* @__PURE__ */ jsxs6("span", { className: "ml-2 text-gray-500", children: [
1073
- "[",
1074
- part.state,
1075
- "]"
1076
- ] }),
1077
- part.errorText && /* @__PURE__ */ jsx9("div", { className: "text-red-600 mt-1", children: part.errorText })
1078
- ] }, key);
1079
1610
  case "dynamic-tool":
1080
1611
  if (renderDynamicTool) {
1081
1612
  return /* @__PURE__ */ jsx9(React10.Fragment, { children: renderDynamicTool(part) }, key);
@@ -1090,6 +1621,21 @@ var Message = React10.forwardRef(
1090
1621
  part.errorText && /* @__PURE__ */ jsx9("div", { className: "text-red-600 mt-1", children: part.errorText })
1091
1622
  ] }, key);
1092
1623
  default:
1624
+ if (part.type.startsWith("tool-") && "toolCallId" in part) {
1625
+ const toolPart = part;
1626
+ if (renderToolCall) {
1627
+ return /* @__PURE__ */ jsx9(React10.Fragment, { children: renderToolCall(toolPart) }, key);
1628
+ }
1629
+ return /* @__PURE__ */ jsxs6("div", { className: "text-xs bg-gray-100 rounded p-2 my-2", children: [
1630
+ /* @__PURE__ */ jsx9("span", { className: "font-mono", children: toolPart.toolName }),
1631
+ /* @__PURE__ */ jsxs6("span", { className: "ml-2 text-gray-500", children: [
1632
+ "[",
1633
+ toolPart.state,
1634
+ "]"
1635
+ ] }),
1636
+ toolPart.errorText && /* @__PURE__ */ jsx9("div", { className: "text-red-600 mt-1", children: toolPart.errorText })
1637
+ ] }, key);
1638
+ }
1093
1639
  return null;
1094
1640
  }
1095
1641
  }),