@agents24/chat-react 0.2.0 → 0.3.1

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),
@@ -883,20 +824,47 @@ var MessageResponse = React3.memo(
883
824
  );
884
825
  MessageResponse.displayName = "MessageResponse";
885
826
 
886
- // 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"];
890
- function asRecord(value) {
891
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
892
- }
827
+ // src/ui/hitl-presentation.ts
893
828
  function optionalString(value) {
894
829
  return typeof value === "string" && value.trim() ? value.trim() : null;
895
830
  }
831
+ function hitlActionLabel(part, action) {
832
+ if (action === "approve") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Allow once" : "Approve";
833
+ if (action === "reject") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Don\u2019t allow" : "Reject";
834
+ if (action === "connect") return "Connect";
835
+ return "Skip";
836
+ }
837
+ function hitlTitle(part) {
838
+ const presentation = part.presentation || {};
839
+ if (part.hitlKind === "tool_review") return `Run ${optionalString(presentation.tool_name) || "this tool"}?`;
840
+ if (part.hitlKind === "mcp_auth") return `Connect ${optionalString(presentation.server_name) || "this service"} to continue`;
841
+ if (part.hitlKind === "app_data_permission") return "Allow this data change?";
842
+ return part.message;
843
+ }
844
+ function resolvedHitlLabel(part) {
845
+ const outcome = String(part.resolution?.outcome || part.status).trim().toLowerCase();
846
+ return {
847
+ approved: part.hitlKind === "user_approval" ? "Approved" : "Allowed",
848
+ rejected: part.hitlKind === "user_approval" ? "Rejected" : "Not allowed",
849
+ connected: "Connected",
850
+ skipped: "Skipped",
851
+ timeout: "Timed out",
852
+ expired: "Timed out",
853
+ cancelled: "Cancelled",
854
+ invalidated: "No longer available",
855
+ policy_denied: "Not allowed"
856
+ }[outcome] || outcome.replace(/_/g, " ");
857
+ }
858
+
859
+ // src/ui/agent-response-timeline.tsx
860
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
861
+ function optionalString2(value) {
862
+ return typeof value === "string" && value.trim() ? value.trim() : null;
863
+ }
896
864
  function presentationValue(part, key) {
897
865
  const presentation = part.presentation || {};
898
866
  const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
899
- return optionalString(presentation[key]) || optionalString(presentation[snakeKey]);
867
+ return optionalString2(presentation[key]) || optionalString2(presentation[snakeKey]);
900
868
  }
901
869
  function groupKey(part) {
902
870
  return presentationValue(part, "groupKey");
@@ -914,7 +882,7 @@ function isActiveTool(part, activeToolId) {
914
882
  return part.id === activeToolId || part.toolCallId === activeToolId || part.state === "input-available" || part.state === "input-streaming";
915
883
  }
916
884
  function Shimmer({ children, className }) {
917
- return /* @__PURE__ */ jsx7("span", { className: cn("inline-block animate-pulse", className), children });
885
+ return /* @__PURE__ */ jsx6("span", { className: cn("inline-block animate-pulse", className), children });
918
886
  }
919
887
  function CompactTask({
920
888
  children,
@@ -926,12 +894,12 @@ function CompactTask({
926
894
  }) {
927
895
  const [open, setOpen] = React4.useState(defaultOpen);
928
896
  const expandable = Boolean(children || detail);
929
- const content = loading ? /* @__PURE__ */ jsx7(Shimmer, { children: label }) : /* @__PURE__ */ jsx7("span", { children: label });
897
+ const content = loading ? /* @__PURE__ */ jsx6(Shimmer, { children: label }) : /* @__PURE__ */ jsx6("span", { children: label });
930
898
  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 });
899
+ 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
900
  }
933
- return /* @__PURE__ */ jsxs4("div", { className: "w-full", children: [
934
- /* @__PURE__ */ jsxs4(
901
+ return /* @__PURE__ */ jsxs3("div", { className: "w-full", children: [
902
+ /* @__PURE__ */ jsxs3(
935
903
  "button",
936
904
  {
937
905
  "aria-expanded": open,
@@ -943,12 +911,12 @@ function CompactTask({
943
911
  type: "button",
944
912
  children: [
945
913
  content,
946
- open ? /* @__PURE__ */ jsx7(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx7(ChevronRight, { className: "size-3 opacity-70" })
914
+ open ? /* @__PURE__ */ jsx6(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx6(ChevronRight, { className: "size-3 opacity-70" })
947
915
  ]
948
916
  }
949
917
  ),
950
- open ? /* @__PURE__ */ jsxs4("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
951
- detail ? /* @__PURE__ */ jsx7("div", { children: detail }) : null,
918
+ open ? /* @__PURE__ */ jsxs3("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
919
+ detail ? /* @__PURE__ */ jsx6("div", { children: detail }) : null,
952
920
  children
953
921
  ] }) : null
954
922
  ] });
@@ -957,7 +925,7 @@ function ToolPartRow({
957
925
  activeToolId,
958
926
  part
959
927
  }) {
960
- return /* @__PURE__ */ jsx7("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsx7(
928
+ return /* @__PURE__ */ jsx6("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ jsx6(
961
929
  CompactTask,
962
930
  {
963
931
  defaultOpen: part.state === "output-error",
@@ -973,41 +941,18 @@ function ToolGroup({
973
941
  parts
974
942
  }) {
975
943
  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(
944
+ return /* @__PURE__ */ jsx6(CompactTask, { label: groupLabel(parts[0]), loading, children: /* @__PURE__ */ jsx6("div", { className: "space-y-1", children: parts.map((part) => /* @__PURE__ */ jsxs3(
977
945
  "div",
978
946
  {
979
947
  className: cn("text-sm", part.state === "output-error" ? "text-destructive" : "text-muted-foreground"),
980
948
  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
949
+ isActiveTool(part, activeToolId) ? /* @__PURE__ */ jsx6(Shimmer, { children: toolLabel(part) }) : toolLabel(part),
950
+ toolDetail(part) ? /* @__PURE__ */ jsx6("span", { className: "ml-1 text-xs text-muted-foreground/75", children: toolDetail(part) }) : null
983
951
  ]
984
952
  },
985
953
  part.id
986
954
  )) }) });
987
955
  }
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";
1010
- }
1011
956
  function HitlPartRow({
1012
957
  getHitlActionState,
1013
958
  isLoading,
@@ -1015,36 +960,40 @@ function HitlPartRow({
1015
960
  part
1016
961
  }) {
1017
962
  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,
963
+ const [comment, setComment] = React4.useState("");
964
+ const presentation = part.presentation || {};
965
+ const requireComment = presentation.require_comment === true;
966
+ const isTerminal = part.status !== "pending";
967
+ if (isTerminal) {
968
+ return /* @__PURE__ */ jsx6("div", { className: "px-1 py-1 text-sm text-muted-foreground", children: resolvedHitlLabel(part) });
969
+ }
970
+ return /* @__PURE__ */ jsxs3("div", { className: "space-y-2.5 rounded-lg bg-muted/45 px-3 py-2.5", children: [
971
+ /* @__PURE__ */ jsx6("div", { className: "text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
972
+ requireComment ? /* @__PURE__ */ jsx6(
973
+ "textarea",
1022
974
  {
1023
- error: state?.error,
1024
- message,
1025
- onConnect: onHitlAction ? () => onHitlAction(part, CONNECT_DECISION) : void 0,
1026
- serverName: mcpConnectLabel(part),
1027
- status: normalizedMcpStatus(state?.status)
975
+ "aria-label": "Approval comment",
976
+ className: "min-h-20 w-full resize-y rounded-md border border-border/60 bg-background px-3 py-2 text-sm outline-none focus-visible:border-neutral-300 focus-visible:ring-0 dark:focus-visible:border-neutral-600",
977
+ onChange: (event) => setComment(event.target.value),
978
+ placeholder: "Comment required",
979
+ value: comment
1028
980
  }
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(
981
+ ) : null,
982
+ state?.error ? /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: state.error }) : null,
983
+ /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ jsx6(
1036
984
  "button",
1037
985
  {
986
+ "aria-label": hitlActionLabel(part, action),
1038
987
  className: cn(
1039
- "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"
988
+ "min-h-10 rounded-md px-3 text-sm font-medium transition-[background-color,color,opacity,transform] duration-150 ease-out active:scale-[0.96] disabled:pointer-events-none disabled:opacity-60",
989
+ action === "approve" || action === "connect" ? "bg-neutral-900 text-white hover:bg-neutral-800 dark:bg-neutral-100 dark:text-neutral-900 dark:hover:bg-white" : "bg-transparent text-muted-foreground hover:bg-background/80 hover:text-foreground"
1041
990
  ),
1042
- disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming",
1043
- onClick: () => onHitlAction?.(part, decision),
991
+ disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming" || requireComment && !comment.trim(),
992
+ onClick: () => onHitlAction?.(part, action, comment.trim() || void 0),
1044
993
  type: "button",
1045
- children: decision === "connect" ? "Connect" : decision
994
+ children: hitlActionLabel(part, action)
1046
995
  },
1047
- decision
996
+ action
1048
997
  )) })
1049
998
  ] });
1050
999
  }
@@ -1056,20 +1005,20 @@ function DefaultPartRow({
1056
1005
  onHitlAction,
1057
1006
  part
1058
1007
  }) {
1059
- if (part.kind === "text") return /* @__PURE__ */ jsx7(MessageResponse, { children: part.text });
1060
- if (part.kind === "tool") return /* @__PURE__ */ jsx7(ToolPartRow, { activeToolId, part });
1008
+ if (part.kind === "text") return /* @__PURE__ */ jsx6(MessageResponse, { children: part.text });
1009
+ if (part.kind === "tool") return /* @__PURE__ */ jsx6(ToolPartRow, { activeToolId, part });
1061
1010
  if (part.kind === "reasoning") {
1062
1011
  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 });
1012
+ 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
1013
  }
1065
1014
  if (part.kind === "ui-blocks") {
1066
1015
  if (part.state === "output-error") {
1067
- return /* @__PURE__ */ jsx7("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1016
+ return /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1068
1017
  }
1069
- return /* @__PURE__ */ jsx7(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1018
+ return /* @__PURE__ */ jsx6(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1070
1019
  }
1071
1020
  if (part.kind === "hitl") {
1072
- return /* @__PURE__ */ jsx7(
1021
+ return /* @__PURE__ */ jsx6(
1073
1022
  HitlPartRow,
1074
1023
  {
1075
1024
  getHitlActionState,
@@ -1079,8 +1028,8 @@ function DefaultPartRow({
1079
1028
  }
1080
1029
  );
1081
1030
  }
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 });
1031
+ if (part.kind === "error") return /* @__PURE__ */ jsx6("div", { className: "text-sm text-destructive", children: part.errorText });
1032
+ if (part.kind === "data") return /* @__PURE__ */ jsx6("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
1084
1033
  return null;
1085
1034
  }
1086
1035
  function AgentResponseTimeline({
@@ -1105,11 +1054,11 @@ function AgentResponseTimeline({
1105
1054
  group.push(candidate);
1106
1055
  index += 1;
1107
1056
  }
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}`));
1057
+ 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
1058
  continue;
1110
1059
  }
1111
1060
  rendered.push(
1112
- /* @__PURE__ */ jsx7(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ jsx7(
1061
+ /* @__PURE__ */ jsx6(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ jsx6(
1113
1062
  DefaultPartRow,
1114
1063
  {
1115
1064
  activeToolId,
@@ -1124,16 +1073,16 @@ function AgentResponseTimeline({
1124
1073
  index += 1;
1125
1074
  }
1126
1075
  if (rendered.length === 0 && message.content) {
1127
- rendered.push(/* @__PURE__ */ jsx7(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1076
+ rendered.push(/* @__PURE__ */ jsx6(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1128
1077
  }
1129
1078
  if (rendered.length === 0 && isLoading) {
1130
- rendered.push(/* @__PURE__ */ jsx7("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1079
+ rendered.push(/* @__PURE__ */ jsx6("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1131
1080
  }
1132
- return /* @__PURE__ */ jsx7("div", { className: "space-y-3", children: rendered });
1081
+ return /* @__PURE__ */ jsx6("div", { className: "space-y-3", children: rendered });
1133
1082
  }
1134
1083
 
1135
1084
  // src/ui/agent-chat-message.tsx
1136
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
1085
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
1137
1086
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
1138
1087
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
1139
1088
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -1156,9 +1105,9 @@ function AgentChatUserMessageContent({
1156
1105
  display: "-webkit-box",
1157
1106
  overflow: "hidden"
1158
1107
  } : 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(
1108
+ return /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-col gap-3", children: [
1109
+ /* @__PURE__ */ jsx7("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
1110
+ shouldCollapse ? /* @__PURE__ */ jsxs4(
1162
1111
  "button",
1163
1112
  {
1164
1113
  "aria-controls": contentId,
@@ -1171,7 +1120,7 @@ function AgentChatUserMessageContent({
1171
1120
  type: "button",
1172
1121
  children: [
1173
1122
  isExpanded ? showLessLabel : showMoreLabel,
1174
- /* @__PURE__ */ jsx8(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1123
+ /* @__PURE__ */ jsx7(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1175
1124
  ]
1176
1125
  }
1177
1126
  ) : null
@@ -1203,9 +1152,9 @@ function AgentChatMessage({
1203
1152
  const resolvedUserContent = userMessageContent ?? message.content;
1204
1153
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
1205
1154
  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(
1155
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ jsx7(AgentChatDefaultActions, { handlers: actionHandlers, message }) : null);
1156
+ return /* @__PURE__ */ jsxs4(ChatMessage, { className, dir, from: message.role, children: [
1157
+ showAttachments ? /* @__PURE__ */ jsx7(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ jsx7(
1209
1158
  ChatAttachment,
1210
1159
  {
1211
1160
  data: attachment,
@@ -1213,13 +1162,13 @@ function AgentChatMessage({
1213
1162
  },
1214
1163
  String(attachment.url || attachment.filename || index)
1215
1164
  )) }) : null,
1216
- shouldRenderContent ? /* @__PURE__ */ jsxs5(
1165
+ shouldRenderContent ? /* @__PURE__ */ jsxs4(
1217
1166
  ChatMessageContent,
1218
1167
  {
1219
1168
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
1220
1169
  dir,
1221
1170
  children: [
1222
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx8(
1171
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ jsx7(
1223
1172
  AgentResponseTimeline,
1224
1173
  {
1225
1174
  getHitlActionState,
@@ -1229,7 +1178,7 @@ function AgentChatMessage({
1229
1178
  renderPart
1230
1179
  }
1231
1180
  ) : null,
1232
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx8(
1181
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ jsx7(
1233
1182
  AgentChatUserMessageContent,
1234
1183
  {
1235
1184
  collapsedLines: userMessageCollapsedLines,
@@ -1242,16 +1191,16 @@ function AgentChatMessage({
1242
1191
  ]
1243
1192
  }
1244
1193
  ) : 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
1194
+ 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
1195
  ] });
1247
1196
  }
1248
1197
 
1249
1198
  // src/ui/bubble.tsx
1250
1199
  import { cva as cva2 } from "class-variance-authority";
1251
1200
  import { Slot as Slot2 } from "@radix-ui/react-slot";
1252
- import { jsx as jsx9 } from "react/jsx-runtime";
1201
+ import { jsx as jsx8 } from "react/jsx-runtime";
1253
1202
  function BubbleGroup({ className, ...props }) {
1254
- return /* @__PURE__ */ jsx9(
1203
+ return /* @__PURE__ */ jsx8(
1255
1204
  "div",
1256
1205
  {
1257
1206
  "data-slot": "bubble-group",
@@ -1285,7 +1234,7 @@ function Bubble({
1285
1234
  className,
1286
1235
  ...props
1287
1236
  }) {
1288
- return /* @__PURE__ */ jsx9(
1237
+ return /* @__PURE__ */ jsx8(
1289
1238
  "div",
1290
1239
  {
1291
1240
  "data-slot": "bubble",
@@ -1302,7 +1251,7 @@ function BubbleContent({
1302
1251
  ...props
1303
1252
  }) {
1304
1253
  const Comp = asChild ? Slot2 : "div";
1305
- return /* @__PURE__ */ jsx9(
1254
+ return /* @__PURE__ */ jsx8(
1306
1255
  Comp,
1307
1256
  {
1308
1257
  "data-slot": "bubble-content",
@@ -1339,7 +1288,7 @@ function BubbleReactions({
1339
1288
  className,
1340
1289
  ...props
1341
1290
  }) {
1342
- return /* @__PURE__ */ jsx9(
1291
+ return /* @__PURE__ */ jsx8(
1343
1292
  "div",
1344
1293
  {
1345
1294
  "data-slot": "bubble-reactions",
@@ -1354,7 +1303,7 @@ function BubbleReactions({
1354
1303
  // src/ui/marker.tsx
1355
1304
  import { cva as cva3 } from "class-variance-authority";
1356
1305
  import { Slot as Slot3 } from "@radix-ui/react-slot";
1357
- import { jsx as jsx10 } from "react/jsx-runtime";
1306
+ import { jsx as jsx9 } from "react/jsx-runtime";
1358
1307
  var markerVariants = cva3(
1359
1308
  "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
1309
  {
@@ -1374,7 +1323,7 @@ function Marker({
1374
1323
  ...props
1375
1324
  }) {
1376
1325
  const Comp = asChild ? Slot3 : "div";
1377
- return /* @__PURE__ */ jsx10(
1326
+ return /* @__PURE__ */ jsx9(
1378
1327
  Comp,
1379
1328
  {
1380
1329
  "data-slot": "marker",
@@ -1385,7 +1334,7 @@ function Marker({
1385
1334
  );
1386
1335
  }
1387
1336
  function MarkerIcon({ className, ...props }) {
1388
- return /* @__PURE__ */ jsx10(
1337
+ return /* @__PURE__ */ jsx9(
1389
1338
  "span",
1390
1339
  {
1391
1340
  "data-slot": "marker-icon",
@@ -1399,7 +1348,7 @@ function MarkerIcon({ className, ...props }) {
1399
1348
  );
1400
1349
  }
1401
1350
  function MarkerContent({ className, ...props }) {
1402
- return /* @__PURE__ */ jsx10(
1351
+ return /* @__PURE__ */ jsx9(
1403
1352
  "span",
1404
1353
  {
1405
1354
  "data-slot": "marker-content",
@@ -1411,6 +1360,65 @@ function MarkerContent({ className, ...props }) {
1411
1360
  }
1412
1361
  );
1413
1362
  }
1363
+
1364
+ // src/ui/mcp-connect-required-card.tsx
1365
+ import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
1366
+ var STATUS_LABELS = {
1367
+ pending: "Connect",
1368
+ connecting: "Connecting",
1369
+ connected: "Connected",
1370
+ resuming: "Resuming",
1371
+ error: "Try again"
1372
+ };
1373
+ function McpConnectRequiredCard({
1374
+ serverName,
1375
+ providerKey,
1376
+ message,
1377
+ status = "pending",
1378
+ disabled = false,
1379
+ loading = false,
1380
+ error,
1381
+ onConnect,
1382
+ className,
1383
+ ...props
1384
+ }) {
1385
+ const label = String(serverName || providerKey || "MCP server").trim();
1386
+ const isBusy = loading || status === "connecting" || status === "resuming";
1387
+ const isConnected = status === "connected";
1388
+ const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
1389
+ return /* @__PURE__ */ jsx10(
1390
+ "div",
1391
+ {
1392
+ "data-agents24-mcp-connect-card": true,
1393
+ "data-status": status,
1394
+ className: cn(
1395
+ "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
1396
+ className
1397
+ ),
1398
+ ...props,
1399
+ children: /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
1400
+ /* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
1401
+ /* @__PURE__ */ jsx10("div", { className: "truncate text-sm font-medium", children: label }),
1402
+ /* @__PURE__ */ jsx10("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
1403
+ status === "error" && error ? /* @__PURE__ */ jsx10("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
1404
+ ] }),
1405
+ /* @__PURE__ */ jsx10(
1406
+ "button",
1407
+ {
1408
+ type: "button",
1409
+ className: cn(
1410
+ "shrink-0 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60",
1411
+ 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"
1412
+ ),
1413
+ disabled: buttonDisabled,
1414
+ onClick: onConnect,
1415
+ children: STATUS_LABELS[status]
1416
+ }
1417
+ )
1418
+ ] })
1419
+ }
1420
+ );
1421
+ }
1414
1422
  export {
1415
1423
  AgentChatComposer,
1416
1424
  AgentChatDefaultActions,
@@ -1458,7 +1466,10 @@ export {
1458
1466
  attachmentVariants,
1459
1467
  bubbleVariants,
1460
1468
  cn,
1469
+ hitlActionLabel,
1470
+ hitlTitle,
1461
1471
  markerVariants,
1472
+ resolvedHitlLabel,
1462
1473
  shouldCollapseUserMessage
1463
1474
  };
1464
1475
  //# sourceMappingURL=index.js.map