@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.cjs CHANGED
@@ -76,7 +76,10 @@ __export(ui_exports, {
76
76
  attachmentVariants: () => attachmentVariants,
77
77
  bubbleVariants: () => bubbleVariants,
78
78
  cn: () => cn,
79
+ hitlActionLabel: () => hitlActionLabel,
80
+ hitlTitle: () => hitlTitle,
79
81
  markerVariants: () => markerVariants,
82
+ resolvedHitlLabel: () => resolvedHitlLabel,
80
83
  shouldCollapseUserMessage: () => shouldCollapseUserMessage
81
84
  });
82
85
  module.exports = __toCommonJS(ui_exports);
@@ -797,65 +800,6 @@ var import_lucide_react4 = require("lucide-react");
797
800
  var React4 = __toESM(require("react"), 1);
798
801
  var import_lucide_react3 = require("lucide-react");
799
802
 
800
- // src/ui/mcp-connect-required-card.tsx
801
- var import_jsx_runtime5 = require("react/jsx-runtime");
802
- var STATUS_LABELS = {
803
- pending: "Connect",
804
- connecting: "Connecting",
805
- connected: "Connected",
806
- resuming: "Resuming",
807
- error: "Try again"
808
- };
809
- function McpConnectRequiredCard({
810
- serverName,
811
- providerKey,
812
- message,
813
- status = "pending",
814
- disabled = false,
815
- loading = false,
816
- error,
817
- onConnect,
818
- className,
819
- ...props
820
- }) {
821
- const label = String(serverName || providerKey || "MCP server").trim();
822
- const isBusy = loading || status === "connecting" || status === "resuming";
823
- const isConnected = status === "connected";
824
- const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
825
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
826
- "div",
827
- {
828
- "data-agents24-mcp-connect-card": true,
829
- "data-status": status,
830
- className: cn(
831
- "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
832
- className
833
- ),
834
- ...props,
835
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
836
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "min-w-0", children: [
837
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "truncate text-sm font-medium", children: label }),
838
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
839
- status === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
840
- ] }),
841
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
842
- "button",
843
- {
844
- type: "button",
845
- className: cn(
846
- "shrink-0 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60",
847
- 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"
848
- ),
849
- disabled: buttonDisabled,
850
- onClick: onConnect,
851
- children: STATUS_LABELS[status]
852
- }
853
- )
854
- ] })
855
- }
856
- );
857
- }
858
-
859
803
  // src/ui/message-response.tsx
860
804
  var React3 = __toESM(require("react"), 1);
861
805
  var import_streamdown = require("streamdown");
@@ -990,7 +934,7 @@ function useStreamingText({
990
934
  }
991
935
 
992
936
  // src/ui/message-response.tsx
993
- var import_jsx_runtime6 = require("react/jsx-runtime");
937
+ var import_jsx_runtime5 = require("react/jsx-runtime");
994
938
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
995
939
  "blockquote",
996
940
  "div",
@@ -1033,12 +977,12 @@ function MessageMarkdownParagraph({
1033
977
  );
1034
978
  const isImageOnly = childArray.length === 1 && React3.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
1035
979
  if (isImageOnly) {
1036
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
980
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
1037
981
  }
1038
982
  if (childArray.some(hasBlockMarkdownChild)) {
1039
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ...domProps, children });
983
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ...domProps, children });
1040
984
  }
1041
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { ...domProps, children });
985
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { ...domProps, children });
1042
986
  }
1043
987
  var MESSAGE_RESPONSE_COMPONENTS = {
1044
988
  p: MessageMarkdownParagraph
@@ -1084,7 +1028,7 @@ var MessageResponse = React3.memo(
1084
1028
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
1085
1029
  [components]
1086
1030
  );
1087
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1031
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1088
1032
  import_streamdown.Streamdown,
1089
1033
  {
1090
1034
  className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
@@ -1099,20 +1043,47 @@ var MessageResponse = React3.memo(
1099
1043
  );
1100
1044
  MessageResponse.displayName = "MessageResponse";
1101
1045
 
1102
- // src/ui/agent-response-timeline.tsx
1103
- var import_jsx_runtime7 = require("react/jsx-runtime");
1104
- var CONNECT_DECISION = "connect";
1105
- var HITL_DECISIONS = ["approve", "edit", "reject", "respond", "connect"];
1106
- function asRecord(value) {
1107
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
1108
- }
1046
+ // src/ui/hitl-presentation.ts
1109
1047
  function optionalString(value) {
1110
1048
  return typeof value === "string" && value.trim() ? value.trim() : null;
1111
1049
  }
1050
+ function hitlActionLabel(part, action) {
1051
+ if (action === "approve") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Allow once" : "Approve";
1052
+ if (action === "reject") return ["tool_review", "app_data_permission"].includes(part.hitlKind) ? "Don\u2019t allow" : "Reject";
1053
+ if (action === "connect") return "Connect";
1054
+ return "Skip";
1055
+ }
1056
+ function hitlTitle(part) {
1057
+ const presentation = part.presentation || {};
1058
+ if (part.hitlKind === "tool_review") return `Run ${optionalString(presentation.tool_name) || "this tool"}?`;
1059
+ if (part.hitlKind === "mcp_auth") return `Connect ${optionalString(presentation.server_name) || "this service"} to continue`;
1060
+ if (part.hitlKind === "app_data_permission") return "Allow this data change?";
1061
+ return part.message;
1062
+ }
1063
+ function resolvedHitlLabel(part) {
1064
+ const outcome = String(part.resolution?.outcome || part.status).trim().toLowerCase();
1065
+ return {
1066
+ approved: part.hitlKind === "user_approval" ? "Approved" : "Allowed",
1067
+ rejected: part.hitlKind === "user_approval" ? "Rejected" : "Not allowed",
1068
+ connected: "Connected",
1069
+ skipped: "Skipped",
1070
+ timeout: "Timed out",
1071
+ expired: "Timed out",
1072
+ cancelled: "Cancelled",
1073
+ invalidated: "No longer available",
1074
+ policy_denied: "Not allowed"
1075
+ }[outcome] || outcome.replace(/_/g, " ");
1076
+ }
1077
+
1078
+ // src/ui/agent-response-timeline.tsx
1079
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1080
+ function optionalString2(value) {
1081
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1082
+ }
1112
1083
  function presentationValue(part, key) {
1113
1084
  const presentation = part.presentation || {};
1114
1085
  const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
1115
- return optionalString(presentation[key]) || optionalString(presentation[snakeKey]);
1086
+ return optionalString2(presentation[key]) || optionalString2(presentation[snakeKey]);
1116
1087
  }
1117
1088
  function groupKey(part) {
1118
1089
  return presentationValue(part, "groupKey");
@@ -1130,7 +1101,7 @@ function isActiveTool(part, activeToolId) {
1130
1101
  return part.id === activeToolId || part.toolCallId === activeToolId || part.state === "input-available" || part.state === "input-streaming";
1131
1102
  }
1132
1103
  function Shimmer({ children, className }) {
1133
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
1104
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
1134
1105
  }
1135
1106
  function CompactTask({
1136
1107
  children,
@@ -1142,12 +1113,12 @@ function CompactTask({
1142
1113
  }) {
1143
1114
  const [open, setOpen] = React4.useState(defaultOpen);
1144
1115
  const expandable = Boolean(children || detail);
1145
- const content = loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Shimmer, { children: label }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: label });
1116
+ const content = loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Shimmer, { children: label }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: label });
1146
1117
  if (!expandable) {
1147
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: cn("flex min-w-0 items-center gap-1.5 text-sm", error ? "text-destructive" : "text-muted-foreground"), children: content });
1118
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: cn("flex min-w-0 items-center gap-1.5 text-sm", error ? "text-destructive" : "text-muted-foreground"), children: content });
1148
1119
  }
1149
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "w-full", children: [
1150
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1120
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "w-full", children: [
1121
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1151
1122
  "button",
1152
1123
  {
1153
1124
  "aria-expanded": open,
@@ -1159,12 +1130,12 @@ function CompactTask({
1159
1130
  type: "button",
1160
1131
  children: [
1161
1132
  content,
1162
- open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react3.ChevronRight, { className: "size-3 opacity-70" })
1133
+ open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.ChevronDown, { className: "size-3" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.ChevronRight, { className: "size-3 opacity-70" })
1163
1134
  ]
1164
1135
  }
1165
1136
  ),
1166
- open ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
1167
- detail ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: detail }) : null,
1137
+ open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "mt-1 pl-4 text-sm text-muted-foreground", children: [
1138
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: detail }) : null,
1168
1139
  children
1169
1140
  ] }) : null
1170
1141
  ] });
@@ -1173,7 +1144,7 @@ function ToolPartRow({
1173
1144
  activeToolId,
1174
1145
  part
1175
1146
  }) {
1176
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1147
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1177
1148
  CompactTask,
1178
1149
  {
1179
1150
  defaultOpen: part.state === "output-error",
@@ -1189,41 +1160,18 @@ function ToolGroup({
1189
1160
  parts
1190
1161
  }) {
1191
1162
  const loading = parts.some((part) => isActiveTool(part, activeToolId));
1192
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CompactTask, { label: groupLabel(parts[0]), loading, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "space-y-1", children: parts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1163
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CompactTask, { label: groupLabel(parts[0]), loading, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-1", children: parts.map((part) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1193
1164
  "div",
1194
1165
  {
1195
1166
  className: cn("text-sm", part.state === "output-error" ? "text-destructive" : "text-muted-foreground"),
1196
1167
  children: [
1197
- isActiveTool(part, activeToolId) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Shimmer, { children: toolLabel(part) }) : toolLabel(part),
1198
- toolDetail(part) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "ml-1 text-xs text-muted-foreground/75", children: toolDetail(part) }) : null
1168
+ isActiveTool(part, activeToolId) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Shimmer, { children: toolLabel(part) }) : toolLabel(part),
1169
+ toolDetail(part) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ml-1 text-xs text-muted-foreground/75", children: toolDetail(part) }) : null
1199
1170
  ]
1200
1171
  },
1201
1172
  part.id
1202
1173
  )) }) });
1203
1174
  }
1204
- function collectHitlDecisions(part) {
1205
- const configs = Array.isArray(part.hitl.review_configs) ? part.hitl.review_configs : [];
1206
- const decisions = configs.flatMap((config) => {
1207
- const record = asRecord(config);
1208
- const allowed = Array.isArray(record?.allowed_decisions) ? record?.allowed_decisions : [];
1209
- return allowed.filter((item) => HITL_DECISIONS.includes(String(item)));
1210
- });
1211
- return Array.from(new Set(decisions));
1212
- }
1213
- function isMcpConnectHitl(part) {
1214
- const kind = `${part.hitlKind || optionalString(part.hitl.kind) || ""}`.toLowerCase();
1215
- const decisions = collectHitlDecisions(part);
1216
- return decisions.includes(CONNECT_DECISION) || kind.includes("mcp") || kind.includes("connection");
1217
- }
1218
- function mcpConnectLabel(part) {
1219
- const payload = asRecord(part.hitl.client_safe_payload);
1220
- const origin = asRecord(part.hitl.origin);
1221
- 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";
1222
- }
1223
- function normalizedMcpStatus(status) {
1224
- if (status === "connecting" || status === "connected" || status === "resuming" || status === "error") return status;
1225
- return "pending";
1226
- }
1227
1175
  function HitlPartRow({
1228
1176
  getHitlActionState,
1229
1177
  isLoading,
@@ -1231,36 +1179,40 @@ function HitlPartRow({
1231
1179
  part
1232
1180
  }) {
1233
1181
  const state = getHitlActionState?.(part);
1234
- const message = optionalString(part.hitl.message) || optionalString(part.hitl.text) || "Input is required to continue.";
1235
- if (isMcpConnectHitl(part)) {
1236
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1237
- McpConnectRequiredCard,
1182
+ const [comment, setComment] = React4.useState("");
1183
+ const presentation = part.presentation || {};
1184
+ const requireComment = presentation.require_comment === true;
1185
+ const isTerminal = part.status !== "pending";
1186
+ if (isTerminal) {
1187
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "px-1 py-1 text-sm text-muted-foreground", children: resolvedHitlLabel(part) });
1188
+ }
1189
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-2.5 rounded-lg bg-muted/45 px-3 py-2.5", children: [
1190
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm font-medium text-foreground text-pretty", children: hitlTitle(part) }),
1191
+ requireComment ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1192
+ "textarea",
1238
1193
  {
1239
- error: state?.error,
1240
- message,
1241
- onConnect: onHitlAction ? () => onHitlAction(part, CONNECT_DECISION) : void 0,
1242
- serverName: mcpConnectLabel(part),
1243
- status: normalizedMcpStatus(state?.status)
1194
+ "aria-label": "Approval comment",
1195
+ 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",
1196
+ onChange: (event) => setComment(event.target.value),
1197
+ placeholder: "Comment required",
1198
+ value: comment
1244
1199
  }
1245
- );
1246
- }
1247
- const decisions = collectHitlDecisions(part);
1248
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-3", children: [
1249
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageResponse, { children: message }),
1250
- state?.error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-destructive", children: state.error }) : null,
1251
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex flex-wrap items-center gap-2", children: decisions.map((decision) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1200
+ ) : null,
1201
+ state?.error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-destructive", children: state.error }) : null,
1202
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-wrap items-center gap-1.5", children: part.allowedActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1252
1203
  "button",
1253
1204
  {
1205
+ "aria-label": hitlActionLabel(part, action),
1254
1206
  className: cn(
1255
- "min-w-24 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:pointer-events-none disabled:opacity-60",
1256
- 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"
1207
+ "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",
1208
+ 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"
1257
1209
  ),
1258
- disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming",
1259
- onClick: () => onHitlAction?.(part, decision),
1210
+ disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming" || requireComment && !comment.trim(),
1211
+ onClick: () => onHitlAction?.(part, action, comment.trim() || void 0),
1260
1212
  type: "button",
1261
- children: decision === "connect" ? "Connect" : decision
1213
+ children: hitlActionLabel(part, action)
1262
1214
  },
1263
- decision
1215
+ action
1264
1216
  )) })
1265
1217
  ] });
1266
1218
  }
@@ -1272,20 +1224,20 @@ function DefaultPartRow({
1272
1224
  onHitlAction,
1273
1225
  part
1274
1226
  }) {
1275
- if (part.kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageResponse, { children: part.text });
1276
- if (part.kind === "tool") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToolPartRow, { activeToolId, part });
1227
+ if (part.kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageResponse, { children: part.text });
1228
+ if (part.kind === "tool") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToolPartRow, { activeToolId, part });
1277
1229
  if (part.kind === "reasoning") {
1278
1230
  const label = part.text || part.label || "Thinking";
1279
- return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-muted-foreground", children: label });
1231
+ return part.status === "running" || part.status === "streaming" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Shimmer, { className: "text-sm text-muted-foreground", children: label }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-muted-foreground", children: label });
1280
1232
  }
1281
1233
  if (part.kind === "ui-blocks") {
1282
1234
  if (part.state === "output-error") {
1283
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1235
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-destructive", children: part.errorText || "Failed to render UI content." });
1284
1236
  }
1285
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1237
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CompactTask, { label: part.state === "input-streaming" ? "Rendering UI block" : "Rendered UI block", loading: part.state === "input-streaming" });
1286
1238
  }
1287
1239
  if (part.kind === "hitl") {
1288
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1240
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1289
1241
  HitlPartRow,
1290
1242
  {
1291
1243
  getHitlActionState,
@@ -1295,8 +1247,8 @@ function DefaultPartRow({
1295
1247
  }
1296
1248
  );
1297
1249
  }
1298
- if (part.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-destructive", children: part.errorText });
1299
- if (part.kind === "data") return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
1250
+ if (part.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-destructive", children: part.errorText });
1251
+ if (part.kind === "data") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { "data-agents24-data-part": part.name, className: "hidden", children: message.id });
1300
1252
  return null;
1301
1253
  }
1302
1254
  function AgentResponseTimeline({
@@ -1321,11 +1273,11 @@ function AgentResponseTimeline({
1321
1273
  group.push(candidate);
1322
1274
  index += 1;
1323
1275
  }
1324
- rendered.push(group.length === 1 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToolPartRow, { activeToolId, part: group[0] }, group[0].id) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToolGroup, { activeToolId, parts: group }, `tool-group-${key}-${group[0].id}`));
1276
+ rendered.push(group.length === 1 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToolPartRow, { activeToolId, part: group[0] }, group[0].id) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToolGroup, { activeToolId, parts: group }, `tool-group-${key}-${group[0].id}`));
1325
1277
  continue;
1326
1278
  }
1327
1279
  rendered.push(
1328
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1280
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1329
1281
  DefaultPartRow,
1330
1282
  {
1331
1283
  activeToolId,
@@ -1340,16 +1292,16 @@ function AgentResponseTimeline({
1340
1292
  index += 1;
1341
1293
  }
1342
1294
  if (rendered.length === 0 && message.content) {
1343
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1295
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1344
1296
  }
1345
1297
  if (rendered.length === 0 && isLoading) {
1346
- rendered.push(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1298
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "text-sm text-muted-foreground", children: "Thinking" }, `${message.id}-thinking`));
1347
1299
  }
1348
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "space-y-3", children: rendered });
1300
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-3", children: rendered });
1349
1301
  }
1350
1302
 
1351
1303
  // src/ui/agent-chat-message.tsx
1352
- var import_jsx_runtime8 = require("react/jsx-runtime");
1304
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1353
1305
  var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
1354
1306
  var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
1355
1307
  function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
@@ -1372,9 +1324,9 @@ function AgentChatUserMessageContent({
1372
1324
  display: "-webkit-box",
1373
1325
  overflow: "hidden"
1374
1326
  } : void 0;
1375
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
1376
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
1377
- shouldCollapse ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1327
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 flex-col gap-3", children: [
1328
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { id: contentId, className: "min-w-0", style: clampedStyle, children: content }),
1329
+ shouldCollapse ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1378
1330
  "button",
1379
1331
  {
1380
1332
  "aria-controls": contentId,
@@ -1387,7 +1339,7 @@ function AgentChatUserMessageContent({
1387
1339
  type: "button",
1388
1340
  children: [
1389
1341
  isExpanded ? showLessLabel : showMoreLabel,
1390
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1342
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1391
1343
  ]
1392
1344
  }
1393
1345
  ) : null
@@ -1419,9 +1371,9 @@ function AgentChatMessage({
1419
1371
  const resolvedUserContent = userMessageContent ?? message.content;
1420
1372
  const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
1421
1373
  const showAttachments = Boolean(message.attachments?.length) && (message.role === "user" || showAssistantAttachments);
1422
- const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AgentChatDefaultActions, { handlers: actionHandlers, message }) : null);
1423
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(ChatMessage, { className, dir, from: message.role, children: [
1424
- showAttachments ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1374
+ const renderedActions = actions ?? (actionHandlers ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AgentChatDefaultActions, { handlers: actionHandlers, message }) : null);
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ChatMessage, { className, dir, from: message.role, children: [
1376
+ showAttachments ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatAttachments, { className: "mb-2", dir, children: message.attachments?.map((attachment, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1425
1377
  ChatAttachment,
1426
1378
  {
1427
1379
  data: attachment,
@@ -1429,13 +1381,13 @@ function AgentChatMessage({
1429
1381
  },
1430
1382
  String(attachment.url || attachment.filename || index)
1431
1383
  )) }) : null,
1432
- shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1384
+ shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1433
1385
  ChatMessageContent,
1434
1386
  {
1435
1387
  className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
1436
1388
  dir,
1437
1389
  children: [
1438
- isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1390
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1439
1391
  AgentResponseTimeline,
1440
1392
  {
1441
1393
  getHitlActionState,
@@ -1445,7 +1397,7 @@ function AgentChatMessage({
1445
1397
  renderPart
1446
1398
  }
1447
1399
  ) : null,
1448
- !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1400
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1449
1401
  AgentChatUserMessageContent,
1450
1402
  {
1451
1403
  collapsedLines: userMessageCollapsedLines,
@@ -1458,16 +1410,16 @@ function AgentChatMessage({
1458
1410
  ]
1459
1411
  }
1460
1412
  ) : null,
1461
- renderedActions ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("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
1413
+ renderedActions ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("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
1462
1414
  ] });
1463
1415
  }
1464
1416
 
1465
1417
  // src/ui/bubble.tsx
1466
1418
  var import_class_variance_authority2 = require("class-variance-authority");
1467
1419
  var import_react_slot2 = require("@radix-ui/react-slot");
1468
- var import_jsx_runtime9 = require("react/jsx-runtime");
1420
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1469
1421
  function BubbleGroup({ className, ...props }) {
1470
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1422
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1471
1423
  "div",
1472
1424
  {
1473
1425
  "data-slot": "bubble-group",
@@ -1501,7 +1453,7 @@ function Bubble({
1501
1453
  className,
1502
1454
  ...props
1503
1455
  }) {
1504
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1456
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1505
1457
  "div",
1506
1458
  {
1507
1459
  "data-slot": "bubble",
@@ -1518,7 +1470,7 @@ function BubbleContent({
1518
1470
  ...props
1519
1471
  }) {
1520
1472
  const Comp = asChild ? import_react_slot2.Slot : "div";
1521
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1473
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1522
1474
  Comp,
1523
1475
  {
1524
1476
  "data-slot": "bubble-content",
@@ -1555,7 +1507,7 @@ function BubbleReactions({
1555
1507
  className,
1556
1508
  ...props
1557
1509
  }) {
1558
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1510
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1559
1511
  "div",
1560
1512
  {
1561
1513
  "data-slot": "bubble-reactions",
@@ -1570,7 +1522,7 @@ function BubbleReactions({
1570
1522
  // src/ui/marker.tsx
1571
1523
  var import_class_variance_authority3 = require("class-variance-authority");
1572
1524
  var import_react_slot3 = require("@radix-ui/react-slot");
1573
- var import_jsx_runtime10 = require("react/jsx-runtime");
1525
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1574
1526
  var markerVariants = (0, import_class_variance_authority3.cva)(
1575
1527
  "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",
1576
1528
  {
@@ -1590,7 +1542,7 @@ function Marker({
1590
1542
  ...props
1591
1543
  }) {
1592
1544
  const Comp = asChild ? import_react_slot3.Slot : "div";
1593
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1545
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1594
1546
  Comp,
1595
1547
  {
1596
1548
  "data-slot": "marker",
@@ -1601,7 +1553,7 @@ function Marker({
1601
1553
  );
1602
1554
  }
1603
1555
  function MarkerIcon({ className, ...props }) {
1604
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1556
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1605
1557
  "span",
1606
1558
  {
1607
1559
  "data-slot": "marker-icon",
@@ -1615,7 +1567,7 @@ function MarkerIcon({ className, ...props }) {
1615
1567
  );
1616
1568
  }
1617
1569
  function MarkerContent({ className, ...props }) {
1618
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1570
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1619
1571
  "span",
1620
1572
  {
1621
1573
  "data-slot": "marker-content",
@@ -1627,6 +1579,65 @@ function MarkerContent({ className, ...props }) {
1627
1579
  }
1628
1580
  );
1629
1581
  }
1582
+
1583
+ // src/ui/mcp-connect-required-card.tsx
1584
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1585
+ var STATUS_LABELS = {
1586
+ pending: "Connect",
1587
+ connecting: "Connecting",
1588
+ connected: "Connected",
1589
+ resuming: "Resuming",
1590
+ error: "Try again"
1591
+ };
1592
+ function McpConnectRequiredCard({
1593
+ serverName,
1594
+ providerKey,
1595
+ message,
1596
+ status = "pending",
1597
+ disabled = false,
1598
+ loading = false,
1599
+ error,
1600
+ onConnect,
1601
+ className,
1602
+ ...props
1603
+ }) {
1604
+ const label = String(serverName || providerKey || "MCP server").trim();
1605
+ const isBusy = loading || status === "connecting" || status === "resuming";
1606
+ const isConnected = status === "connected";
1607
+ const buttonDisabled = disabled || isBusy || isConnected || !onConnect;
1608
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1609
+ "div",
1610
+ {
1611
+ "data-agents24-mcp-connect-card": true,
1612
+ "data-status": status,
1613
+ className: cn(
1614
+ "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
1615
+ className
1616
+ ),
1617
+ ...props,
1618
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [
1619
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "min-w-0", children: [
1620
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "truncate text-sm font-medium", children: label }),
1621
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-1 text-sm text-muted-foreground", children: message || "Connect your account to continue." }),
1622
+ status === "error" && error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2 text-sm text-destructive", children: error }) : null
1623
+ ] }),
1624
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1625
+ "button",
1626
+ {
1627
+ type: "button",
1628
+ className: cn(
1629
+ "shrink-0 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-60",
1630
+ 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"
1631
+ ),
1632
+ disabled: buttonDisabled,
1633
+ onClick: onConnect,
1634
+ children: STATUS_LABELS[status]
1635
+ }
1636
+ )
1637
+ ] })
1638
+ }
1639
+ );
1640
+ }
1630
1641
  // Annotate the CommonJS export names for ESM import in node:
1631
1642
  0 && (module.exports = {
1632
1643
  AgentChatComposer,
@@ -1675,7 +1686,10 @@ function MarkerContent({ className, ...props }) {
1675
1686
  attachmentVariants,
1676
1687
  bubbleVariants,
1677
1688
  cn,
1689
+ hitlActionLabel,
1690
+ hitlTitle,
1678
1691
  markerVariants,
1692
+ resolvedHitlLabel,
1679
1693
  shouldCollapseUserMessage
1680
1694
  });
1681
1695
  //# sourceMappingURL=index.cjs.map