@agents24/chat-react 0.2.0 → 0.3.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/ui/index.js CHANGED
@@ -712,69 +712,10 @@ import { ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
712
712
  import * as React4 from "react";
713
713
  import { ChevronDown, ChevronRight } from "lucide-react";
714
714
 
715
- // src/ui/mcp-connect-required-card.tsx
716
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
717
- var STATUS_LABELS = {
718
- pending: "Connect",
719
- connecting: "Connecting",
720
- connected: "Connected",
721
- resuming: "Resuming",
722
- error: "Try again"
723
- };
724
- function McpConnectRequiredCard({
725
- serverName,
726
- providerKey,
727
- message,
728
- status = "pending",
729
- disabled = false,
730
- loading = false,
731
- error,
732
- onConnect,
733
- className,
734
- ...props
735
- }) {
736
- const label = String(serverName || providerKey || "MCP server").trim();
737
- const isBusy = loading || status === "connecting" || status === "resuming";
738
- const isConnected = status === "connected";
739
- const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
740
- return /* @__PURE__ */ jsx5(
741
- "div",
742
- {
743
- "data-agents24-mcp-connect-card": true,
744
- "data-status": status,
745
- className: cn(
746
- "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
747
- className
748
- ),
749
- ...props,
750
- children: /* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
751
- /* @__PURE__ */ jsxs3("div", { className: "min-w-0", children: [
752
- /* @__PURE__ */ jsx5("div", { className: "truncate text-sm font-medium", children: label }),
753
- /* @__PURE__ */ jsx5("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
754
- status === "error" && error ? /* @__PURE__ */ jsx5("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
755
- ] }),
756
- /* @__PURE__ */ jsx5(
757
- "button",
758
- {
759
- type: "button",
760
- className: cn(
761
- "shrink-0 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60",
762
- status === "pending" || status === "error" ? "border-neutral-900 bg-neutral-900 text-white hover:bg-neutral-800" : "border-border bg-background text-foreground hover:bg-muted"
763
- ),
764
- disabled: buttonDisabled,
765
- onClick: onConnect,
766
- children: STATUS_LABELS[status]
767
- }
768
- )
769
- ] })
770
- }
771
- );
772
- }
773
-
774
715
  // src/ui/message-response.tsx
775
716
  import * as React3 from "react";
776
717
  import { defaultRehypePlugins, Streamdown } from "streamdown";
777
- import { Fragment, jsx as jsx6 } from "react/jsx-runtime";
718
+ import { Fragment, jsx as jsx5 } from "react/jsx-runtime";
778
719
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
779
720
  "blockquote",
780
721
  "div",
@@ -817,12 +758,12 @@ function MessageMarkdownParagraph({
817
758
  );
818
759
  const isImageOnly = childArray.length === 1 && React3.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
819
760
  if (isImageOnly) {
820
- return /* @__PURE__ */ jsx6(Fragment, { children });
761
+ return /* @__PURE__ */ jsx5(Fragment, { children });
821
762
  }
822
763
  if (childArray.some(hasBlockMarkdownChild)) {
823
- return /* @__PURE__ */ jsx6("div", { ...domProps, children });
764
+ return /* @__PURE__ */ jsx5("div", { ...domProps, children });
824
765
  }
825
- return /* @__PURE__ */ jsx6("p", { ...domProps, children });
766
+ return /* @__PURE__ */ jsx5("p", { ...domProps, children });
826
767
  }
827
768
  var MESSAGE_RESPONSE_COMPONENTS = {
828
769
  p: MessageMarkdownParagraph
@@ -868,7 +809,7 @@ var MessageResponse = React3.memo(
868
809
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
869
810
  [components]
870
811
  );
871
- return /* @__PURE__ */ jsx6(
812
+ return /* @__PURE__ */ jsx5(
872
813
  Streamdown,
873
814
  {
874
815
  className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
@@ -884,9 +825,7 @@ var MessageResponse = React3.memo(
884
825
  MessageResponse.displayName = "MessageResponse";
885
826
 
886
827
  // src/ui/agent-response-timeline.tsx
887
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
888
- var CONNECT_DECISION = "connect";
889
- var HITL_DECISIONS = ["approve", "edit", "reject", "respond", "connect"];
828
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
890
829
  function asRecord(value) {
891
830
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
892
831
  }
@@ -914,7 +853,7 @@ function isActiveTool(part, activeToolId) {
914
853
  return part.id === activeToolId || part.toolCallId === activeToolId || part.state === "input-available" || part.state === "input-streaming";
915
854
  }
916
855
  function Shimmer({ children, className }) {
917
- return /* @__PURE__ */ jsx7("span", { className: cn("inline-block animate-pulse", className), children });
856
+ return /* @__PURE__ */ jsx6("span", { className: cn("inline-block animate-pulse", className), children });
918
857
  }
919
858
  function CompactTask({
920
859
  children,
@@ -926,12 +865,12 @@ function CompactTask({
926
865
  }) {
927
866
  const [open, setOpen] = React4.useState(defaultOpen);
928
867
  const expandable = Boolean(children || detail);
929
- const content = loading ? /* @__PURE__ */ jsx7(Shimmer, { children: label }) : /* @__PURE__ */ jsx7("span", { children: label });
868
+ const content = loading ? /* @__PURE__ */ jsx6(Shimmer, { children: label }) : /* @__PURE__ */ jsx6("span", { children: label });
930
869
  if (!expandable) {
931
- return /* @__PURE__ */ jsx7("div", { className: cn("flex min-w-0 items-center gap-1.5 text-sm", error ? "text-destructive" : "text-muted-foreground"), children: content });
870
+ return /* @__PURE__ */ jsx6("div", { className: cn("flex min-w-0 items-center gap-1.5 text-sm", error ? "text-destructive" : "text-muted-foreground"), children: content });
932
871
  }
933
- return /* @__PURE__ */ jsxs4("div", { className: "w-full", children: [
934
- /* @__PURE__ */ jsxs4(
872
+ return /* @__PURE__ */ jsxs3("div", { className: "w-full", children: [
873
+ /* @__PURE__ */ jsxs3(
935
874
  "button",
936
875
  {
937
876
  "aria-expanded": open,
@@ -943,12 +882,12 @@ function CompactTask({
943
882
  type: "button",
944
883
  children: [
945
884
  content,
946
- open ? /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx7(ChevronRight, { className: "size-3 opacity-70" })
885
+ open ? /* @__PURE__ */ jsx6(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx6(ChevronRight, { className: "size-3 opacity-70" })
947
886
  ]
948
887
  }
949
888
  ),
950
- open ? /* @__PURE__ */ jsxs4("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
951
- detail ? /* @__PURE__ */ jsx7("div", { children: detail }) : null,
889
+ open ? /* @__PURE__ */ jsxs3("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
890
+ detail ? /* @__PURE__ */ jsx6("div", { children: detail }) : null,
952
891
  children
953
892
  ] }) : null
954
893
  ] });
@@ -957,7 +896,7 @@ function ToolPartRow({
957
896
  activeToolId,
958
897
  part
959
898
  }) {
960
- return /* @__PURE__ */ jsx7("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsx7(
899
+ return /* @__PURE__ */ jsx6("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsx6(
961
900
  CompactTask,
962
901
  {
963
902
  defaultOpen: part.state === "output-error",
@@ -973,40 +912,23 @@ function ToolGroup({
973
912
  parts
974
913
  }) {
975
914
  const loading = parts.some((part) => isActiveTool(part, activeToolId));
976
- return /* @__PURE__ */ jsx7(CompactTask, { label: groupLabel(parts[0]), loading, children: /* @__PURE__ */ jsx7("div", { className: "space-y-1", children: parts.map((part) => /* @__PURE__ */ jsxs4(
915
+ return /* @__PURE__ */ jsx6(CompactTask, { label: groupLabel(parts[0]), loading, children: /* @__PURE__ */ jsx6("div", { className: "space-y-1", children: parts.map((part) => /* @__PURE__ */ jsxs3(
977
916
  "div",
978
917
  {
979
918
  className: cn("text-sm", part.state === "output-error" ? "text-destructive" : "text-muted-foreground"),
980
919
  children: [
981
- isActiveTool(part, activeToolId) ? /* @__PURE__ */ jsx7(Shimmer, { children: toolLabel(part) }) : toolLabel(part),
982
- toolDetail(part) ? /* @__PURE__ */ jsx7("span", { className: "ml-1 text-xs text-muted-foreground/75", children: toolDetail(part) }) : null
920
+ isActiveTool(part, activeToolId) ? /* @__PURE__ */ jsx6(Shimmer, { children: toolLabel(part) }) : toolLabel(part),
921
+ toolDetail(part) ? /* @__PURE__ */ jsx6("span", { className: "ml-1 text-xs text-muted-foreground/75", children: toolDetail(part) }) : null
983
922
  ]
984
923
  },
985
924
  part.id
986
925
  )) }) });
987
926
  }
988
- function collectHitlDecisions(part) {
989
- const configs = Array.isArray(part.hitl.review_configs) ? part.hitl.review_configs : [];
990
- const decisions = configs.flatMap((config) => {
991
- const record = asRecord(config);
992
- const allowed = Array.isArray(record?.allowed_decisions) ? record?.allowed_decisions : [];
993
- return allowed.filter((item) => HITL_DECISIONS.includes(String(item)));
994
- });
995
- return Array.from(new Set(decisions));
996
- }
997
- function isMcpConnectHitl(part) {
998
- const kind = `${part.hitlKind || optionalString(part.hitl.kind) || ""}`.toLowerCase();
999
- const decisions = collectHitlDecisions(part);
1000
- return decisions.includes(CONNECT_DECISION) || kind.includes("mcp") || kind.includes("connection");
1001
- }
1002
- function mcpConnectLabel(part) {
1003
- const payload = asRecord(part.hitl.client_safe_payload);
1004
- const origin = asRecord(part.hitl.origin);
1005
- return optionalString(part.hitl.server_name) || optionalString(part.hitl.provider_name) || optionalString(payload?.server_name) || optionalString(payload?.provider_name) || optionalString(origin?.server_name) || optionalString(origin?.provider_name) || "MCP server";
1006
- }
1007
- function normalizedMcpStatus(status) {
1008
- if (status === "connecting" || status === "connected" || status === "resuming" || status === "error") return status;
1009
- return "pending";
927
+ function actionLabel(part, action) {
928
+ if (action === "approve") return part.hitlKind === "tool_review" ? "Allow once" : "Approve";
929
+ if (action === "reject") return part.hitlKind === "tool_review" ? "Don\u2019t allow" : "Reject";
930
+ if (action === "connect") return "Connect";
931
+ return "Skip";
1010
932
  }
1011
933
  function HitlPartRow({
1012
934
  getHitlActionState,
@@ -1015,36 +937,68 @@ function HitlPartRow({
1015
937
  part
1016
938
  }) {
1017
939
  const state = getHitlActionState?.(part);
1018
- const message = optionalString(part.hitl.message) || optionalString(part.hitl.text) || "Input is required to continue.";
1019
- if (isMcpConnectHitl(part)) {
1020
- return /* @__PURE__ */ jsx7(
1021
- McpConnectRequiredCard,
940
+ const [comment, setComment] = React4.useState("");
941
+ const presentation = part.presentation || {};
942
+ const details = asRecord(presentation.sanitized_arguments);
943
+ const requireComment = presentation.require_comment === true;
944
+ const isTerminal = part.status !== "pending";
945
+ if (isTerminal) {
946
+ return /* @__PURE__ */ jsxs3("div", { className: "rounded-xl border border-border/60 bg-muted/30 px-3 py-2 text-sm text-muted-foreground", children: [
947
+ /* @__PURE__ */ jsx6("span", { className: "font-medium text-foreground", children: part.resolution?.outcome || part.status }),
948
+ part.resolution?.reason ? /* @__PURE__ */ jsxs3("span", { className: "ml-1", children: [
949
+ "\xB7 ",
950
+ part.resolution.reason
951
+ ] }) : null
952
+ ] });
953
+ }
954
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-3 rounded-xl border border-amber-500/30 bg-amber-500/5 p-3", children: [
955
+ /* @__PURE__ */ jsxs3("div", { className: "space-y-1", children: [
956
+ /* @__PURE__ */ jsx6("div", { className: "text-sm font-semibold text-foreground", children: optionalString(presentation.tool_name) || optionalString(presentation.server_name) || "Action required" }),
957
+ /* @__PURE__ */ jsx6(MessageResponse, { children: part.message }),
958
+ /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground", children: [
959
+ optionalString(presentation.source) ? /* @__PURE__ */ jsxs3("span", { children: [
960
+ "Source: ",
961
+ optionalString(presentation.source)
962
+ ] }) : null,
963
+ optionalString(presentation.risk) ? /* @__PURE__ */ jsxs3("span", { children: [
964
+ "Risk: ",
965
+ optionalString(presentation.risk)
966
+ ] }) : null,
967
+ optionalString(presentation.credential_scope) ? /* @__PURE__ */ jsxs3("span", { children: [
968
+ "Credentials: ",
969
+ optionalString(presentation.credential_scope)
970
+ ] }) : null
971
+ ] })
972
+ ] }),
973
+ details ? /* @__PURE__ */ jsxs3("details", { className: "text-xs text-muted-foreground", children: [
974
+ /* @__PURE__ */ jsx6("summary", { className: "cursor-pointer select-none font-medium", children: "Details" }),
975
+ /* @__PURE__ */ jsx6("pre", { className: "mt-2 max-h-48 overflow-auto rounded-lg bg-background/80 p-2 text-[11px]", children: JSON.stringify(details, null, 2) })
976
+ ] }) : null,
977
+ requireComment ? /* @__PURE__ */ jsx6(
978
+ "textarea",
1022
979
  {
1023
- error: state?.error,
1024
- message,
1025
- onConnect: onHitlAction ? () => onHitlAction(part, CONNECT_DECISION) : void 0,
1026
- serverName: mcpConnectLabel(part),
1027
- status: normalizedMcpStatus(state?.status)
980
+ "aria-label": "Approval comment",
981
+ className: "min-h-20 w-full resize-y rounded-lg border border-border bg-background px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
982
+ onChange: (event) => setComment(event.target.value),
983
+ placeholder: "Comment required",
984
+ value: comment
1028
985
  }
1029
- );
1030
- }
1031
- const decisions = collectHitlDecisions(part);
1032
- return /* @__PURE__ */ jsxs4("div", { className: "space-y-3", children: [
1033
- /* @__PURE__ */ jsx7(MessageResponse, { children: message }),
1034
- state?.error ? /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", children: state.error }) : null,
1035
- /* @__PURE__ */ jsx7("div", { className: "flex flex-wrap items-center gap-2", children: decisions.map((decision) => /* @__PURE__ */ jsx7(
986
+ ) : null,
987
+ state?.error ? /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: state.error }) : null,
988
+ /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap items-center gap-2", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx6(
1036
989
  "button",
1037
990
  {
991
+ "aria-label": actionLabel(part, action),
1038
992
  className: cn(
1039
993
  "min-w-24 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-60",
1040
- decision === "approve" || decision === "connect" ? "border-neutral-900 bg-neutral-900 text-white hover:bg-neutral-800" : "border-border bg-background text-foreground hover:bg-muted"
994
+ action === "approve" || action === "connect" ? "border-neutral-900 bg-neutral-900 text-white hover:bg-neutral-800" : "border-border bg-background text-foreground hover:bg-muted"
1041
995
  ),
1042
- disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming",
1043
- onClick: () => onHitlAction?.(part, decision),
996
+ disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming" || requireComment && !comment.trim(),
997
+ onClick: () => onHitlAction?.(part, action, comment.trim() || void 0),
1044
998
  type: "button",
1045
- children: decision === "connect" ? "Connect" : decision
999
+ children: actionLabel(part, action)
1046
1000
  },
1047
- decision
1001
+ action
1048
1002
  )) })
1049
1003
  ] });
1050
1004
  }
@@ -1056,20 +1010,20 @@ function DefaultPartRow({
1056
1010
  onHitlAction,
1057
1011
  part
1058
1012
  }) {
1059
- if (part.kind === "text") return /* @__PURE__ */ jsx7(MessageResponse, { children: part.text });
1060
- if (part.kind === "tool") return /* @__PURE__ */ jsx7(ToolPartRow, { activeToolId, part });
1013
+ if (part.kind === "text") return /* @__PURE__ */ jsx6(MessageResponse, { children: part.text });
1014
+ if (part.kind === "tool") return /* @__PURE__ */ jsx6(ToolPartRow, { activeToolId, part });
1061
1015
  if (part.kind === "reasoning") {
1062
1016
  const label = part.text || part.label || "Thinking";
1063
- return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx7(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx7("div", { className: "text-sm text-muted-foreground", children: label });
1017
+ return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ jsx6(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ jsx6("div", { className: "text-sm text-muted-foreground", children: label });
1064
1018
  }
1065
1019
  if (part.kind === "ui-blocks") {
1066
1020
  if (part.state === "output-error") {
1067
- return /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1021
+ return /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1068
1022
  }
1069
- return /* @__PURE__ */ jsx7(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1023
+ return /* @__PURE__ */ jsx6(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1070
1024
  }
1071
1025
  if (part.kind === "hitl") {
1072
- return /* @__PURE__ */ jsx7(
1026
+ return /* @__PURE__ */ jsx6(
1073
1027
  HitlPartRow,
1074
1028
  {
1075
1029
  getHitlActionState,
@@ -1079,8 +1033,8 @@ function DefaultPartRow({
1079
1033
  }
1080
1034
  );
1081
1035
  }
1082
- if (part.kind === "error") return /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", children: part.errorText });
1083
- if (part.kind === "data") return /* @__PURE__ */ jsx7("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
1036
+ if (part.kind === "error") return /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: part.errorText });
1037
+ if (part.kind === "data") return /* @__PURE__ */ jsx6("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
1084
1038
  return null;
1085
1039
  }
1086
1040
  function AgentResponseTimeline({
@@ -1105,11 +1059,11 @@ function AgentResponseTimeline({
1105
1059
  group.push(candidate);
1106
1060
  index += 1;
1107
1061
  }
1108
- rendered.push(group.length === 1 ? /* @__PURE__ */ jsx7(ToolPartRow, { activeToolId, part: group[0] }, group[0].id) : /* @__PURE__ */ jsx7(ToolGroup, { activeToolId, parts: group }, `tool-group-${key}-${group[0].id}`));
1062
+ rendered.push(group.length === 1 ? /* @__PURE__ */ jsx6(ToolPartRow, { activeToolId, part: group[0] }, group[0].id) : /* @__PURE__ */ jsx6(ToolGroup, { activeToolId, parts: group }, `tool-group-${key}-${group[0].id}`));
1109
1063
  continue;
1110
1064
  }
1111
1065
  rendered.push(
1112
- /* @__PURE__ */ jsx7(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ jsx7(
1066
+ /* @__PURE__ */ jsx6(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ jsx6(
1113
1067
  DefaultPartRow,
1114
1068
  {
1115
1069
  activeToolId,
@@ -1124,16 +1078,16 @@ function AgentResponseTimeline({
1124
1078
  index += 1;
1125
1079
  }
1126
1080
  if (rendered.length === 0 && message.content) {
1127
- rendered.push(/* @__PURE__ */ jsx7(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1081
+ rendered.push(/* @__PURE__ */ jsx6(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1128
1082
  }
1129
1083
  if (rendered.length === 0 && isLoading) {
1130
- rendered.push(/* @__PURE__ */ jsx7("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1084
+ rendered.push(/* @__PURE__ */ jsx6("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1131
1085
  }
1132
- return /* @__PURE__ */ jsx7("div", { className: "space-y-3", children: rendered });
1086
+ return /* @__PURE__ */ jsx6("div", { className: "space-y-3", children: rendered });
1133
1087
  }
1134
1088
 
1135
1089
  // src/ui/agent-chat-message.tsx
1136
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1090
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1137
1091
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
1138
1092
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
1139
1093
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -1156,9 +1110,9 @@ function AgentChatUserMessageContent({
1156
1110
  display: "-webkit-box",
1157
1111
  overflow: "hidden"
1158
1112
  } : void 0;
1159
- return /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 flex-col gap-3", children: [
1160
- /* @__PURE__ */ jsx8("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
1161
- shouldCollapse ? /* @__PURE__ */ jsxs5(
1113
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-col gap-3", children: [
1114
+ /* @__PURE__ */ jsx7("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
1115
+ shouldCollapse ? /* @__PURE__ */ jsxs4(
1162
1116
  "button",
1163
1117
  {
1164
1118
  "aria-controls": contentId,
@@ -1171,7 +1125,7 @@ function AgentChatUserMessageContent({
1171
1125
  type: "button",
1172
1126
  children: [
1173
1127
  isExpanded ? showLessLabel : showMoreLabel,
1174
- /* @__PURE__ */ jsx8(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1128
+ /* @__PURE__ */ jsx7(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1175
1129
  ]
1176
1130
  }
1177
1131
  ) : null
@@ -1203,9 +1157,9 @@ function AgentChatMessage({
1203
1157
  const resolvedUserContent = userMessageContent ?? message.content;
1204
1158
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
1205
1159
  const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
1206
- const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx8(AgentChatDefaultActions, { handlers: actionHandlers, message }) : null);
1207
- return /* @__PURE__ */ jsxs5(ChatMessage, { className, dir, from: message.role, children: [
1208
- showAttachments ? /* @__PURE__ */ jsx8(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ jsx8(
1160
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx7(AgentChatDefaultActions, { handlers: actionHandlers, message }) : null);
1161
+ return /* @__PURE__ */ jsxs4(ChatMessage, { className, dir, from: message.role, children: [
1162
+ showAttachments ? /* @__PURE__ */ jsx7(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ jsx7(
1209
1163
  ChatAttachment,
1210
1164
  {
1211
1165
  data: attachment,
@@ -1213,13 +1167,13 @@ function AgentChatMessage({
1213
1167
  },
1214
1168
  String(attachment.url || attachment.filename || index)
1215
1169
  )) }) : null,
1216
- shouldRenderContent ? /* @__PURE__ */ jsxs5(
1170
+ shouldRenderContent ? /* @__PURE__ */ jsxs4(
1217
1171
  ChatMessageContent,
1218
1172
  {
1219
1173
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
1220
1174
  dir,
1221
1175
  children: [
1222
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx8(
1176
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx7(
1223
1177
  AgentResponseTimeline,
1224
1178
  {
1225
1179
  getHitlActionState,
@@ -1229,7 +1183,7 @@ function AgentChatMessage({
1229
1183
  renderPart
1230
1184
  }
1231
1185
  ) : null,
1232
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx8(
1186
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx7(
1233
1187
  AgentChatUserMessageContent,
1234
1188
  {
1235
1189
  collapsedLines: userMessageCollapsedLines,
@@ -1242,16 +1196,16 @@ function AgentChatMessage({
1242
1196
  ]
1243
1197
  }
1244
1198
  ) : null,
1245
- renderedActions ? /* @__PURE__ */ jsx8("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full translate-x-2" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
1199
+ renderedActions ? /* @__PURE__ */ jsx7("div", { className: cn(dir === "rtl" ? "mt-1 h-9 w-full translate-x-2" : "mt-1 h-9 w-full -translate-x-2", actionsClassName), children: renderedActions }) : null
1246
1200
  ] });
1247
1201
  }
1248
1202
 
1249
1203
  // src/ui/bubble.tsx
1250
1204
  import { cva as cva2 } from "class-variance-authority";
1251
1205
  import { Slot as Slot2 } from "@radix-ui/react-slot";
1252
- import { jsx as jsx9 } from "react/jsx-runtime";
1206
+ import { jsx as jsx8 } from "react/jsx-runtime";
1253
1207
  function BubbleGroup({ className, ...props }) {
1254
- return /* @__PURE__ */ jsx9(
1208
+ return /* @__PURE__ */ jsx8(
1255
1209
  "div",
1256
1210
  {
1257
1211
  "data-slot": "bubble-group",
@@ -1285,7 +1239,7 @@ function Bubble({
1285
1239
  className,
1286
1240
  ...props
1287
1241
  }) {
1288
- return /* @__PURE__ */ jsx9(
1242
+ return /* @__PURE__ */ jsx8(
1289
1243
  "div",
1290
1244
  {
1291
1245
  "data-slot": "bubble",
@@ -1302,7 +1256,7 @@ function BubbleContent({
1302
1256
  ...props
1303
1257
  }) {
1304
1258
  const Comp = asChild ? Slot2 : "div";
1305
- return /* @__PURE__ */ jsx9(
1259
+ return /* @__PURE__ */ jsx8(
1306
1260
  Comp,
1307
1261
  {
1308
1262
  "data-slot": "bubble-content",
@@ -1339,7 +1293,7 @@ function BubbleReactions({
1339
1293
  className,
1340
1294
  ...props
1341
1295
  }) {
1342
- return /* @__PURE__ */ jsx9(
1296
+ return /* @__PURE__ */ jsx8(
1343
1297
  "div",
1344
1298
  {
1345
1299
  "data-slot": "bubble-reactions",
@@ -1354,7 +1308,7 @@ function BubbleReactions({
1354
1308
  // src/ui/marker.tsx
1355
1309
  import { cva as cva3 } from "class-variance-authority";
1356
1310
  import { Slot as Slot3 } from "@radix-ui/react-slot";
1357
- import { jsx as jsx10 } from "react/jsx-runtime";
1311
+ import { jsx as jsx9 } from "react/jsx-runtime";
1358
1312
  var markerVariants = cva3(
1359
1313
  "group/marker relative flex min-h-4 w-full items-center gap-2 text-left text-sm text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [a]:underline [a]:underline-offset-3 [a]:hover:text-foreground",
1360
1314
  {
@@ -1374,7 +1328,7 @@ function Marker({
1374
1328
  ...props
1375
1329
  }) {
1376
1330
  const Comp = asChild ? Slot3 : "div";
1377
- return /* @__PURE__ */ jsx10(
1331
+ return /* @__PURE__ */ jsx9(
1378
1332
  Comp,
1379
1333
  {
1380
1334
  "data-slot": "marker",
@@ -1385,7 +1339,7 @@ function Marker({
1385
1339
  );
1386
1340
  }
1387
1341
  function MarkerIcon({ className, ...props }) {
1388
- return /* @__PURE__ */ jsx10(
1342
+ return /* @__PURE__ */ jsx9(
1389
1343
  "span",
1390
1344
  {
1391
1345
  "data-slot": "marker-icon",
@@ -1399,7 +1353,7 @@ function MarkerIcon({ className, ...props }) {
1399
1353
  );
1400
1354
  }
1401
1355
  function MarkerContent({ className, ...props }) {
1402
- return /* @__PURE__ */ jsx10(
1356
+ return /* @__PURE__ */ jsx9(
1403
1357
  "span",
1404
1358
  {
1405
1359
  "data-slot": "marker-content",
@@ -1411,6 +1365,65 @@ function MarkerContent({ className, ...props }) {
1411
1365
  }
1412
1366
  );
1413
1367
  }
1368
+
1369
+ // src/ui/mcp-connect-required-card.tsx
1370
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1371
+ var STATUS_LABELS = {
1372
+ pending: "Connect",
1373
+ connecting: "Connecting",
1374
+ connected: "Connected",
1375
+ resuming: "Resuming",
1376
+ error: "Try again"
1377
+ };
1378
+ function McpConnectRequiredCard({
1379
+ serverName,
1380
+ providerKey,
1381
+ message,
1382
+ status = "pending",
1383
+ disabled = false,
1384
+ loading = false,
1385
+ error,
1386
+ onConnect,
1387
+ className,
1388
+ ...props
1389
+ }) {
1390
+ const label = String(serverName || providerKey || "MCP server").trim();
1391
+ const isBusy = loading || status === "connecting" || status === "resuming";
1392
+ const isConnected = status === "connected";
1393
+ const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
1394
+ return /* @__PURE__ */ jsx10(
1395
+ "div",
1396
+ {
1397
+ "data-agents24-mcp-connect-card": true,
1398
+ "data-status": status,
1399
+ className: cn(
1400
+ "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
1401
+ className
1402
+ ),
1403
+ ...props,
1404
+ children: /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
1405
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1406
+ /* @__PURE__ */ jsx10("div", { className: "truncate text-sm font-medium", children: label }),
1407
+ /* @__PURE__ */ jsx10("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
1408
+ status === "error" && error ? /* @__PURE__ */ jsx10("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
1409
+ ] }),
1410
+ /* @__PURE__ */ jsx10(
1411
+ "button",
1412
+ {
1413
+ type: "button",
1414
+ className: cn(
1415
+ "shrink-0 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60",
1416
+ status === "pending" || status === "error" ? "border-neutral-900 bg-neutral-900 text-white hover:bg-neutral-800" : "border-border bg-background text-foreground hover:bg-muted"
1417
+ ),
1418
+ disabled: buttonDisabled,
1419
+ onClick: onConnect,
1420
+ children: STATUS_LABELS[status]
1421
+ }
1422
+ )
1423
+ ] })
1424
+ }
1425
+ );
1426
+ }
1414
1427
  export {
1415
1428
  AgentChatComposer,
1416
1429
  AgentChatDefaultActions,