@agents24/chat-react 0.1.9 → 0.1.10

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
@@ -30,6 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/ui/index.ts
31
31
  var ui_exports = {};
32
32
  __export(ui_exports, {
33
+ AgentChatComposer: () => AgentChatComposer,
34
+ AgentChatDefaultActions: () => AgentChatDefaultActions,
35
+ AgentChatMessage: () => AgentChatMessage,
36
+ AgentChatPartRow: () => DefaultPartRow,
37
+ AgentChatUserMessageContent: () => AgentChatUserMessageContent,
38
+ AgentResponseTimeline: () => AgentResponseTimeline,
33
39
  Attachment: () => Attachment,
34
40
  AttachmentAction: () => AttachmentAction,
35
41
  AttachmentActions: () => AttachmentActions,
@@ -52,6 +58,7 @@ __export(ui_exports, {
52
58
  Marker: () => Marker,
53
59
  MarkerContent: () => MarkerContent,
54
60
  MarkerIcon: () => MarkerIcon,
61
+ McpConnectRequiredCard: () => McpConnectRequiredCard,
55
62
  Message: () => ChatMessage,
56
63
  MessageAction: () => ChatMessageAction,
57
64
  MessageActions: () => ChatMessageActions,
@@ -69,16 +76,14 @@ __export(ui_exports, {
69
76
  attachmentVariants: () => attachmentVariants,
70
77
  bubbleVariants: () => bubbleVariants,
71
78
  cn: () => cn,
72
- markerVariants: () => markerVariants
79
+ markerVariants: () => markerVariants,
80
+ shouldCollapseUserMessage: () => shouldCollapseUserMessage
73
81
  });
74
82
  module.exports = __toCommonJS(ui_exports);
75
83
 
76
- // src/ui/adapters.ts
84
+ // src/ui/agent-chat-composer.tsx
77
85
  var React = __toESM(require("react"), 1);
78
-
79
- // src/ui/attachment.tsx
80
- var import_class_variance_authority = require("class-variance-authority");
81
- var import_react_slot = require("@radix-ui/react-slot");
86
+ var import_lucide_react = require("lucide-react");
82
87
 
83
88
  // src/ui/utils.ts
84
89
  var import_clsx = require("clsx");
@@ -87,10 +92,258 @@ function cn(...values) {
87
92
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(values));
88
93
  }
89
94
 
90
- // src/ui/attachment.tsx
95
+ // src/ui/agent-chat-composer.tsx
91
96
  var import_jsx_runtime = require("react/jsx-runtime");
97
+ var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`;
98
+ function createComposerFile(file) {
99
+ return {
100
+ id: createId(),
101
+ type: "file",
102
+ url: URL.createObjectURL(file),
103
+ filename: file.name || "attachment",
104
+ mediaType: file.type || "application/octet-stream"
105
+ };
106
+ }
107
+ function revokeComposerFiles(files) {
108
+ files.forEach((file) => {
109
+ try {
110
+ URL.revokeObjectURL(file.url);
111
+ } catch {
112
+ }
113
+ });
114
+ }
115
+ function formatFileCount(files) {
116
+ if (files.length === 1) return files[0].filename;
117
+ return `${files.length} files`;
118
+ }
119
+ var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-full border-0 bg-neutral-100 text-sm text-neutral-600 shadow-none transition-colors hover:bg-neutral-200 hover:text-neutral-800 focus-visible:border-neutral-300 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700";
120
+ var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-full border-0 bg-neutral-900 text-sm text-white shadow-none transition-all duration-200 hover:bg-neutral-800 hover:text-white focus-visible:border-neutral-300 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50 dark:bg-neutral-100 dark:text-neutral-900 dark:hover:bg-white";
121
+ function AgentChatComposer({
122
+ accept,
123
+ allowAttachments = true,
124
+ attachmentLayout = "flow",
125
+ className,
126
+ disabled = false,
127
+ inputToolbarContent,
128
+ isRunning = false,
129
+ onAttachmentCountChange,
130
+ onStop,
131
+ onSubmit,
132
+ placeholder = "Send follow-up",
133
+ textareaRef
134
+ }) {
135
+ const fileInputRef = React.useRef(null);
136
+ const filesRef = React.useRef([]);
137
+ const localTextareaRef = React.useRef(null);
138
+ const [text, setText] = React.useState("");
139
+ const [files, setFiles] = React.useState([]);
140
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
141
+ const isExpanded = text.includes("\n") || text.length > 62;
142
+ const setTextareaRef = React.useCallback(
143
+ (node) => {
144
+ localTextareaRef.current = node;
145
+ if (typeof textareaRef === "function") {
146
+ textareaRef(node);
147
+ } else if (textareaRef) {
148
+ textareaRef.current = node;
149
+ }
150
+ },
151
+ [textareaRef]
152
+ );
153
+ React.useEffect(() => {
154
+ filesRef.current = files;
155
+ onAttachmentCountChange?.(files.length);
156
+ }, [files, onAttachmentCountChange]);
157
+ React.useEffect(() => () => revokeComposerFiles(filesRef.current), []);
158
+ React.useLayoutEffect(() => {
159
+ const textarea = localTextareaRef.current;
160
+ if (!textarea) return;
161
+ if (isExpanded) {
162
+ textarea.style.height = "auto";
163
+ const scrollHeight = textarea.scrollHeight;
164
+ textarea.style.height = `${Math.min(scrollHeight, 224)}px`;
165
+ textarea.style.overflowY = scrollHeight >= 224 ? "auto" : "hidden";
166
+ return;
167
+ }
168
+ textarea.style.height = "";
169
+ textarea.style.overflowY = "hidden";
170
+ }, [isExpanded, text]);
171
+ const canSubmit = !disabled && !isSubmitting && !isRunning && (text.trim().length > 0 || files.length > 0);
172
+ const handleFilesChange = (event) => {
173
+ const selected = Array.from(event.target.files || []).map(createComposerFile);
174
+ if (selected.length > 0) {
175
+ setFiles((current) => [...current, ...selected]);
176
+ }
177
+ event.currentTarget.value = "";
178
+ };
179
+ const removeFile = (fileId) => {
180
+ setFiles((current) => {
181
+ const target = current.find((file) => file.id === fileId);
182
+ if (target) revokeComposerFiles([target]);
183
+ return current.filter((file) => file.id !== fileId);
184
+ });
185
+ };
186
+ const submit = async () => {
187
+ if (!canSubmit) return;
188
+ const submittedText = text.trim();
189
+ const submittedFiles = files;
190
+ setIsSubmitting(true);
191
+ try {
192
+ await onSubmit({ text: submittedText, files: submittedFiles });
193
+ setText("");
194
+ setFiles([]);
195
+ revokeComposerFiles(submittedFiles);
196
+ } finally {
197
+ setIsSubmitting(false);
198
+ }
199
+ };
200
+ const handleKeyDown = (event) => {
201
+ if (event.key === "Enter" && !event.shiftKey) {
202
+ event.preventDefault();
203
+ void submit();
204
+ }
205
+ };
206
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cn("relative mx-auto w-full max-w-3xl overflow-visible", className), children: [
207
+ files.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
208
+ "div",
209
+ {
210
+ "data-testid": "agent-chat-composer-attachments",
211
+ className: cn(
212
+ "flex min-w-0 gap-2 py-1",
213
+ attachmentLayout === "overlay" ? "absolute bottom-full left-0 right-0 mb-1.5 flex-nowrap overflow-x-auto overflow-y-hidden overscroll-x-contain px-2" : "mb-2 flex-wrap px-1"
214
+ ),
215
+ children: files.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
216
+ "div",
217
+ {
218
+ className: "group relative flex h-8 max-w-[min(20rem,calc(100vw-2rem))] cursor-default select-none items-center gap-1.5 rounded-md border border-neutral-200 bg-white px-1.5 text-sm font-medium text-foreground transition-colors hover:bg-neutral-50",
219
+ children: [
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "flex size-5 shrink-0 items-center justify-center rounded bg-background text-muted-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Paperclip, { className: "size-3" }) }),
221
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "min-w-0 flex-1 truncate", children: file.filename }),
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
223
+ "button",
224
+ {
225
+ "aria-label": `Remove ${file.filename}`,
226
+ className: "inline-flex size-5 shrink-0 items-center justify-center rounded text-muted-foreground opacity-70 transition-colors hover:bg-muted hover:text-foreground hover:opacity-100 focus-visible:outline-none",
227
+ onClick: () => removeFile(file.id),
228
+ type: "button",
229
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "size-3" })
230
+ }
231
+ )
232
+ ]
233
+ },
234
+ file.id
235
+ ))
236
+ }
237
+ ) : null,
238
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
239
+ "div",
240
+ {
241
+ className: cn(
242
+ "relative w-full border border-neutral-200 bg-white shadow-sm transition-colors duration-200 focus-within:border-neutral-300 dark:border-neutral-700 dark:bg-card dark:focus-within:border-neutral-600",
243
+ isExpanded ? "rounded-[18px] p-2 pb-1.5" : "rounded-full px-2 py-[3px]"
244
+ ),
245
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
246
+ "div",
247
+ {
248
+ className: "w-full",
249
+ style: {
250
+ alignItems: "center",
251
+ display: "grid",
252
+ gridTemplateAreas: isExpanded ? `"textarea textarea textarea" "plus toolbar submit"` : `"plus textarea composer mic submit"`,
253
+ gridTemplateColumns: isExpanded ? "auto 1fr auto" : "auto 1fr auto auto auto",
254
+ gap: isExpanded ? "3px 10px" : "8px"
255
+ },
256
+ children: [
257
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { gridArea: "plus" }, className: "flex shrink-0 items-center justify-center", children: [
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
259
+ "input",
260
+ {
261
+ ref: fileInputRef,
262
+ accept,
263
+ "aria-label": "Attach files",
264
+ className: "hidden",
265
+ multiple: true,
266
+ onChange: handleFilesChange,
267
+ type: "file"
268
+ }
269
+ ),
270
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
271
+ "button",
272
+ {
273
+ "aria-label": "Attach files",
274
+ className: pillButtonClass,
275
+ disabled: disabled || isSubmitting || isRunning || !allowAttachments,
276
+ onClick: () => fileInputRef.current?.click(),
277
+ title: "Attach files",
278
+ type: "button",
279
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Plus, { className: "size-4" })
280
+ }
281
+ )
282
+ ] }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridArea: "textarea" }, className: "min-w-0 w-full", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
284
+ "textarea",
285
+ {
286
+ ref: setTextareaRef,
287
+ "aria-label": "Message",
288
+ className: cn(
289
+ "w-full resize-none border-0 bg-transparent px-1 text-[15px] leading-relaxed text-foreground shadow-none outline-none placeholder:text-neutral-400 focus-visible:ring-0 scrollbar-thin",
290
+ isExpanded ? "min-h-9 max-h-[224px] py-1" : "min-h-9 h-9 max-h-9 py-2"
291
+ ),
292
+ disabled: disabled || isSubmitting || isRunning,
293
+ onChange: (event) => setText(event.target.value),
294
+ onKeyDown: handleKeyDown,
295
+ placeholder,
296
+ rows: isExpanded ? 2 : 1,
297
+ value: text
298
+ }
299
+ ) }),
300
+ isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridArea: "toolbar" }, className: "flex min-w-0 items-center gap-1.5", children: inputToolbarContent }) : null,
301
+ !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
302
+ !isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end" }) : null,
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { gridArea: "submit" }, className: "flex shrink-0 items-center justify-end", children: isRunning ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
304
+ "button",
305
+ {
306
+ "aria-label": "Stop generating",
307
+ className: submitButtonClass,
308
+ disabled: disabled || !onStop,
309
+ onClick: onStop,
310
+ title: "Stop",
311
+ type: "button",
312
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Square, { className: "size-3.5 fill-current" })
313
+ }
314
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
315
+ "button",
316
+ {
317
+ "aria-label": files.length > 0 ? `Send ${formatFileCount(files)}` : "Send message",
318
+ className: cn(submitButtonClass, text.trim().length > 0 && "hover:scale-105"),
319
+ disabled: !canSubmit,
320
+ onClick: () => void submit(),
321
+ title: "Send",
322
+ type: "button",
323
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUp, { className: "size-4", strokeWidth: 2.5 })
324
+ }
325
+ ) })
326
+ ]
327
+ }
328
+ )
329
+ }
330
+ ),
331
+ !isExpanded && inputToolbarContent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
332
+ ] });
333
+ }
334
+
335
+ // src/ui/agent-chat-actions.tsx
336
+ var import_lucide_react2 = require("lucide-react");
337
+
338
+ // src/ui/adapters.ts
339
+ var React2 = __toESM(require("react"), 1);
340
+
341
+ // src/ui/attachment.tsx
342
+ var import_class_variance_authority = require("class-variance-authority");
343
+ var import_react_slot = require("@radix-ui/react-slot");
344
+ var import_jsx_runtime2 = require("react/jsx-runtime");
92
345
  var attachmentVariants = (0, import_class_variance_authority.cva)(
93
- "group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:ring-1 focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
346
+ "group/attachment relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border bg-card text-card-foreground transition-colors focus-within:border-neutral-300 focus-within:ring-0 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
94
347
  {
95
348
  variants: {
96
349
  size: {
@@ -112,7 +365,7 @@ function Attachment({
112
365
  orientation = "horizontal",
113
366
  ...props
114
367
  }) {
115
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
368
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
116
369
  "div",
117
370
  {
118
371
  "data-slot": "attachment",
@@ -143,7 +396,7 @@ function AttachmentMedia({
143
396
  variant = "icon",
144
397
  ...props
145
398
  }) {
146
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
399
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
147
400
  "div",
148
401
  {
149
402
  "data-slot": "attachment-media",
@@ -157,7 +410,7 @@ function AttachmentContent({
157
410
  className,
158
411
  ...props
159
412
  }) {
160
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
413
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
161
414
  "div",
162
415
  {
163
416
  "data-slot": "attachment-content",
@@ -173,7 +426,7 @@ function AttachmentTitle({
173
426
  className,
174
427
  ...props
175
428
  }) {
176
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
429
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
177
430
  "span",
178
431
  {
179
432
  "data-slot": "attachment-title",
@@ -189,7 +442,7 @@ function AttachmentDescription({
189
442
  className,
190
443
  ...props
191
444
  }) {
192
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
445
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
193
446
  "span",
194
447
  {
195
448
  "data-slot": "attachment-description",
@@ -206,7 +459,7 @@ function AttachmentActions({
206
459
  className,
207
460
  ...props
208
461
  }) {
209
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
462
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
210
463
  "div",
211
464
  {
212
465
  "data-slot": "attachment-actions",
@@ -223,13 +476,13 @@ function AttachmentAction({
223
476
  type = "button",
224
477
  ...props
225
478
  }) {
226
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
479
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
227
480
  "button",
228
481
  {
229
482
  "data-slot": "attachment-action",
230
483
  type,
231
484
  className: cn(
232
- "inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
485
+ "inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:border-neutral-300 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50",
233
486
  className
234
487
  ),
235
488
  ...props
@@ -243,7 +496,7 @@ function AttachmentTrigger({
243
496
  ...props
244
497
  }) {
245
498
  const Comp = asChild ? import_react_slot.Slot : "button";
246
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
499
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
247
500
  Comp,
248
501
  {
249
502
  "data-slot": "attachment-trigger",
@@ -254,7 +507,7 @@ function AttachmentTrigger({
254
507
  );
255
508
  }
256
509
  function AttachmentGroup({ className, ...props }) {
257
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
510
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
258
511
  "div",
259
512
  {
260
513
  "data-slot": "attachment-group",
@@ -267,111 +520,6 @@ function AttachmentGroup({ className, ...props }) {
267
520
  );
268
521
  }
269
522
 
270
- // src/ui/bubble.tsx
271
- var import_class_variance_authority2 = require("class-variance-authority");
272
- var import_react_slot2 = require("@radix-ui/react-slot");
273
- var import_jsx_runtime2 = require("react/jsx-runtime");
274
- function BubbleGroup({ className, ...props }) {
275
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
276
- "div",
277
- {
278
- "data-slot": "bubble-group",
279
- className: cn("flex min-w-0 flex-col gap-2", className),
280
- ...props
281
- }
282
- );
283
- }
284
- var bubbleVariants = (0, import_class_variance_authority2.cva)(
285
- "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
286
- {
287
- variants: {
288
- variant: {
289
- default: "*:data-[slot=bubble-content]:bg-primary *:data-[slot=bubble-content]:text-primary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-primary/80",
290
- secondary: "*:data-[slot=bubble-content]:bg-secondary *:data-[slot=bubble-content]:text-secondary-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]",
291
- muted: "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
292
- tinted: "*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.93_calc(c*0.4)_h)] *:data-[slot=bubble-content]:text-foreground dark:*:data-[slot=bubble-content]:bg-[oklch(from_var(--primary)_0.3_calc(c*0.4)_h)] [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.88_calc(c*0.5)_h)] dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-[oklch(from_var(--primary)_0.35_calc(c*0.5)_h)]",
293
- outline: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
294
- ghost: "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
295
- destructive: "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30"
296
- }
297
- },
298
- defaultVariants: {
299
- variant: "default"
300
- }
301
- }
302
- );
303
- function Bubble({
304
- variant = "default",
305
- align = "start",
306
- className,
307
- ...props
308
- }) {
309
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
310
- "div",
311
- {
312
- "data-slot": "bubble",
313
- "data-variant": variant,
314
- "data-align": align,
315
- className: cn(bubbleVariants({ variant }), className),
316
- ...props
317
- }
318
- );
319
- }
320
- function BubbleContent({
321
- asChild = false,
322
- className,
323
- ...props
324
- }) {
325
- const Comp = asChild ? import_react_slot2.Slot : "div";
326
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
327
- Comp,
328
- {
329
- "data-slot": "bubble-content",
330
- className: cn(
331
- "w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50",
332
- className
333
- ),
334
- ...props
335
- }
336
- );
337
- }
338
- var bubbleReactionsVariants = (0, import_class_variance_authority2.cva)(
339
- "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
340
- {
341
- variants: {
342
- side: {
343
- top: "top-0 -translate-y-3/4",
344
- bottom: "bottom-0 translate-y-3/4"
345
- },
346
- align: {
347
- start: "left-3",
348
- end: "right-3"
349
- }
350
- },
351
- defaultVariants: {
352
- side: "bottom",
353
- align: "end"
354
- }
355
- }
356
- );
357
- function BubbleReactions({
358
- side = "bottom",
359
- align = "end",
360
- className,
361
- ...props
362
- }) {
363
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
364
- "div",
365
- {
366
- "data-slot": "bubble-reactions",
367
- "data-align": align,
368
- "data-side": side,
369
- className: cn(bubbleReactionsVariants({ side, align }), className),
370
- ...props
371
- }
372
- );
373
- }
374
-
375
523
  // src/ui/message.tsx
376
524
  var import_jsx_runtime3 = require("react/jsx-runtime");
377
525
  function MessageGroup({ className, ...props }) {
@@ -464,25 +612,25 @@ function ChatMessage(input) {
464
612
  const messageProps = Object.assign({}, props);
465
613
  messageProps.align = resolvedAlign;
466
614
  messageProps.className = cn(
467
- "group flex w-full flex-col gap-2 overflow-visible",
468
- isUser ? cn("is-user max-w-[80%] justify-end", isRtl ? "mr-auto" : "ml-auto") : "is-assistant max-w-full",
615
+ "group flex w-full max-w-[80%] flex-col gap-2",
616
+ isUser ? cn("is-user justify-end", isRtl ? "mr-auto" : "ml-auto") : "is-assistant",
469
617
  className
470
618
  );
471
- return React.createElement(Message, messageProps);
619
+ return React2.createElement(Message, messageProps);
472
620
  }
473
621
  function ChatMessageContent({
474
622
  className,
475
623
  ...props
476
624
  }) {
477
- return React.createElement(BubbleContent, {
625
+ return React2.createElement("div", {
478
626
  className: cn(
479
- "flex w-full max-w-full min-w-0 flex-col gap-2 text-sm",
480
- "group-[.is-user]:w-fit group-[.is-user]:overflow-visible group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
481
- "group-[.is-assistant]:w-full group-[.is-assistant]:max-w-full group-[.is-assistant]:overflow-hidden group-[.is-assistant]:text-foreground",
482
- props.dir === "rtl" ? "group-[.is-assistant]:pr-0" : "group-[.is-assistant]:pl-0",
627
+ "is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden text-sm",
628
+ "group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
629
+ "group-[.is-assistant]:w-full group-[.is-assistant]:max-w-full group-[.is-assistant]:text-foreground",
483
630
  props.dir === "rtl" ? "group-[.is-user]:mr-auto" : "group-[.is-user]:ml-auto",
484
631
  className
485
632
  ),
633
+ "data-slot": "message-content",
486
634
  ...props
487
635
  });
488
636
  }
@@ -490,7 +638,7 @@ function ChatMessageActions({
490
638
  className,
491
639
  ...props
492
640
  }) {
493
- return React.createElement("div", {
641
+ return React2.createElement("div", {
494
642
  className: cn("flex items-center gap-1", className),
495
643
  "data-slot": "message-actions",
496
644
  ...props
@@ -505,12 +653,12 @@ function ChatMessageAction({
505
653
  ...props
506
654
  }) {
507
655
  const tooltipLabel = typeof tooltip === "string" ? tooltip : void 0;
508
- return React.createElement(
656
+ return React2.createElement(
509
657
  "button",
510
658
  {
511
659
  "aria-label": label || tooltipLabel,
512
660
  className: cn(
513
- "inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
661
+ "inline-flex size-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:border-neutral-300 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50",
514
662
  className
515
663
  ),
516
664
  title: tooltipLabel,
@@ -518,7 +666,7 @@ function ChatMessageAction({
518
666
  ...props
519
667
  },
520
668
  children,
521
- React.createElement(
669
+ React2.createElement(
522
670
  "span",
523
671
  { className: "sr-only" },
524
672
  label || tooltipLabel
@@ -534,32 +682,32 @@ function ChatAttachment({
534
682
  const mediaType = data.mediaType || data.contentType || String(data.type || "application/octet-stream");
535
683
  const filename = data.filename || data.name || "Attachment";
536
684
  const isImage = mediaType.startsWith("image/") && Boolean(data.url);
537
- return React.createElement(
685
+ return React2.createElement(
538
686
  Attachment,
539
687
  {
540
688
  orientation: orientation || (isImage ? "vertical" : "horizontal"),
541
689
  ...props
542
690
  },
543
- React.createElement(
691
+ React2.createElement(
544
692
  AttachmentMedia,
545
693
  { variant: isImage ? "image" : "icon" },
546
- isImage ? React.createElement("img", {
694
+ isImage ? React2.createElement("img", {
547
695
  alt: filename,
548
696
  className: "size-full object-cover",
549
697
  src: data.url
550
- }) : React.createElement(
698
+ }) : React2.createElement(
551
699
  "span",
552
700
  { "aria-hidden": "true", className: "text-sm" },
553
701
  filename.slice(0, 1).toUpperCase()
554
702
  )
555
703
  ),
556
- React.createElement(
704
+ React2.createElement(
557
705
  AttachmentContent,
558
706
  null,
559
- React.createElement(AttachmentTitle, null, filename),
560
- React.createElement(AttachmentDescription, null, mediaType)
707
+ React2.createElement(AttachmentTitle, null, filename),
708
+ React2.createElement(AttachmentDescription, null, mediaType)
561
709
  ),
562
- onRemove ? React.createElement(
710
+ onRemove ? React2.createElement(
563
711
  "button",
564
712
  {
565
713
  "aria-label": "Remove attachment",
@@ -570,7 +718,7 @@ function ChatAttachment({
570
718
  },
571
719
  type: "button"
572
720
  },
573
- React.createElement("span", { "aria-hidden": "true" }, "x")
721
+ React2.createElement("span", { "aria-hidden": "true" }, "x")
574
722
  ) : null
575
723
  );
576
724
  }
@@ -580,7 +728,7 @@ function ChatAttachments({
580
728
  ...props
581
729
  }) {
582
730
  if (!children) return null;
583
- return React.createElement(
731
+ return React2.createElement(
584
732
  AttachmentGroup,
585
733
  {
586
734
  className: cn(
@@ -594,69 +742,122 @@ function ChatAttachments({
594
742
  );
595
743
  }
596
744
 
597
- // src/ui/marker.tsx
598
- var import_class_variance_authority3 = require("class-variance-authority");
599
- var import_react_slot3 = require("@radix-ui/react-slot");
745
+ // src/ui/agent-chat-actions.tsx
600
746
  var import_jsx_runtime4 = require("react/jsx-runtime");
601
- var markerVariants = (0, import_class_variance_authority3.cva)(
602
- "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",
603
- {
604
- variants: {
605
- variant: {
606
- default: "",
607
- separator: "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border",
608
- border: "border-b border-border pb-2"
747
+ function AgentChatDefaultActions({
748
+ handlers,
749
+ message
750
+ }) {
751
+ if (!handlers || message.role !== "assistant" || message.isFinal === false) return null;
752
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(ChatMessageActions, { children: [
753
+ handlers.onRetry ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
754
+ ChatMessageAction,
755
+ {
756
+ label: "Retry",
757
+ onClick: () => void handlers.onRetry?.(message),
758
+ tooltip: "Regenerate response",
759
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.RefreshCcw, { className: "size-4" })
609
760
  }
610
- }
611
- }
612
- );
613
- function Marker({
761
+ ) : null,
762
+ handlers.onLike ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
763
+ ChatMessageAction,
764
+ {
765
+ label: "Like",
766
+ onClick: () => void handlers.onLike?.(message),
767
+ tooltip: "Like this response",
768
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsUp, { className: "size-4", fill: handlers.liked ? "currentColor" : "none" })
769
+ }
770
+ ) : null,
771
+ handlers.onDislike ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
772
+ ChatMessageAction,
773
+ {
774
+ label: "Dislike",
775
+ onClick: () => void handlers.onDislike?.(message),
776
+ tooltip: "Dislike this response",
777
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.ThumbsDown, { className: "size-4", fill: handlers.disliked ? "currentColor" : "none" })
778
+ }
779
+ ) : null,
780
+ handlers.onCopy ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
781
+ ChatMessageAction,
782
+ {
783
+ label: "Copy",
784
+ onClick: () => handlers.onCopy?.(message.content || "", message.id),
785
+ tooltip: handlers.copied ? "Copied!" : "Copy to clipboard",
786
+ children: handlers.copied ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Check, { className: "size-4 text-green-600" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react2.Copy, { className: "size-4" })
787
+ }
788
+ ) : null
789
+ ] });
790
+ }
791
+
792
+ // src/ui/agent-chat-message.tsx
793
+ var React5 = __toESM(require("react"), 1);
794
+ var import_lucide_react4 = require("lucide-react");
795
+
796
+ // src/ui/agent-response-timeline.tsx
797
+ var React4 = __toESM(require("react"), 1);
798
+ var import_lucide_react3 = require("lucide-react");
799
+
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,
614
818
  className,
615
- variant = "default",
616
- asChild = false,
617
819
  ...props
618
820
  }) {
619
- const Comp = asChild ? import_react_slot3.Slot : "div";
620
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
621
- Comp,
622
- {
623
- "data-slot": "marker",
624
- "data-variant": variant,
625
- className: cn(markerVariants({ variant, className })),
626
- ...props
627
- }
628
- );
629
- }
630
- function MarkerIcon({ className, ...props }) {
631
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
632
- "span",
633
- {
634
- "data-slot": "marker-icon",
635
- "aria-hidden": "true",
636
- className: cn(
637
- "size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4",
638
- className
639
- ),
640
- ...props
641
- }
642
- );
643
- }
644
- function MarkerContent({ className, ...props }) {
645
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
646
- "span",
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",
647
827
  {
648
- "data-slot": "marker-content",
828
+ "data-agents24-mcp-connect-card": true,
829
+ "data-status": status,
649
830
  className: cn(
650
- "min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
831
+ "w-full rounded-lg border border-border/50 bg-muted/25 p-3 text-sm text-foreground",
651
832
  className
652
833
  ),
653
- ...props
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
+ ] })
654
855
  }
655
856
  );
656
857
  }
657
858
 
658
859
  // src/ui/message-response.tsx
659
- var React2 = __toESM(require("react"), 1);
860
+ var React3 = __toESM(require("react"), 1);
660
861
  var import_streamdown = require("streamdown");
661
862
 
662
863
  // src/streaming-text.ts
@@ -789,7 +990,7 @@ function useStreamingText({
789
990
  }
790
991
 
791
992
  // src/ui/message-response.tsx
792
- var import_jsx_runtime5 = require("react/jsx-runtime");
993
+ var import_jsx_runtime6 = require("react/jsx-runtime");
793
994
  var BLOCK_MARKDOWN_TAGS = /* @__PURE__ */ new Set([
794
995
  "blockquote",
795
996
  "div",
@@ -809,7 +1010,7 @@ function isMultilineCodeNode(node) {
809
1010
  return node?.tagName === "code" && node.position?.start?.line !== void 0 && node.position?.end?.line !== void 0 && node.position.start.line !== node.position.end.line;
810
1011
  }
811
1012
  function hasBlockMarkdownChild(child) {
812
- if (!React2.isValidElement(child)) {
1013
+ if (!React3.isValidElement(child)) {
813
1014
  return false;
814
1015
  }
815
1016
  if (typeof child.type === "string" && BLOCK_MARKDOWN_TAGS.has(child.type)) {
@@ -819,7 +1020,7 @@ function hasBlockMarkdownChild(child) {
819
1020
  if (BLOCK_MARKDOWN_TAGS.has(props.node?.tagName || "") || isMultilineCodeNode(props.node)) {
820
1021
  return true;
821
1022
  }
822
- return React2.Children.toArray(props.children).some(hasBlockMarkdownChild);
1023
+ return React3.Children.toArray(props.children).some(hasBlockMarkdownChild);
823
1024
  }
824
1025
  function MessageMarkdownParagraph({
825
1026
  children,
@@ -827,17 +1028,17 @@ function MessageMarkdownParagraph({
827
1028
  }) {
828
1029
  const domProps = { ...props };
829
1030
  delete domProps.node;
830
- const childArray = React2.Children.toArray(children).filter(
1031
+ const childArray = React3.Children.toArray(children).filter(
831
1032
  (child) => child !== null && child !== ""
832
1033
  );
833
- const isImageOnly = childArray.length === 1 && React2.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
1034
+ const isImageOnly = childArray.length === 1 && React3.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
834
1035
  if (isImageOnly) {
835
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
1036
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
836
1037
  }
837
1038
  if (childArray.some(hasBlockMarkdownChild)) {
838
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ...domProps, children });
1039
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ...domProps, children });
839
1040
  }
840
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { ...domProps, children });
1041
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { ...domProps, children });
841
1042
  }
842
1043
  var MESSAGE_RESPONSE_COMPONENTS = {
843
1044
  p: MessageMarkdownParagraph
@@ -861,7 +1062,7 @@ var MESSAGE_RESPONSE_REHYPE_PLUGINS = [
861
1062
  ]
862
1063
  ] : []
863
1064
  ];
864
- var MessageResponse = React2.memo(
1065
+ var MessageResponse = React3.memo(
865
1066
  ({
866
1067
  children,
867
1068
  className,
@@ -879,11 +1080,11 @@ var MessageResponse = React2.memo(
879
1080
  maxCatchupChars: 32,
880
1081
  text
881
1082
  });
882
- const streamdownComponents = React2.useMemo(
1083
+ const streamdownComponents = React3.useMemo(
883
1084
  () => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
884
1085
  [components]
885
1086
  );
886
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
887
1088
  import_streamdown.Streamdown,
888
1089
  {
889
1090
  className: cn("size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", className),
@@ -897,8 +1098,543 @@ var MessageResponse = React2.memo(
897
1098
  (prevProps, nextProps) => prevProps.children === nextProps.children && prevProps.className === nextProps.className && prevProps.streaming === nextProps.streaming && prevProps.streamingId === nextProps.streamingId && prevProps.components === nextProps.components
898
1099
  );
899
1100
  MessageResponse.displayName = "MessageResponse";
1101
+
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
+ }
1109
+ function optionalString(value) {
1110
+ return typeof value === "string" && value.trim() ? value.trim() : null;
1111
+ }
1112
+ function presentationValue(part, key) {
1113
+ const presentation = part.presentation || {};
1114
+ const snakeKey = key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
1115
+ return optionalString(presentation[key]) || optionalString(presentation[snakeKey]);
1116
+ }
1117
+ function groupKey(part) {
1118
+ return presentationValue(part, "groupKey");
1119
+ }
1120
+ function groupLabel(part) {
1121
+ return presentationValue(part, "groupLabel") || toolLabel(part);
1122
+ }
1123
+ function toolLabel(part) {
1124
+ return presentationValue(part, "activity") || presentationValue(part, "title") || part.toolName || "Tool activity";
1125
+ }
1126
+ function toolDetail(part) {
1127
+ return presentationValue(part, "detail") || part.errorText || null;
1128
+ }
1129
+ function isActiveTool(part, activeToolId) {
1130
+ return part.id === activeToolId || part.toolCallId === activeToolId || part.state === "input-available" || part.state === "input-streaming";
1131
+ }
1132
+ function Shimmer({ children, className }) {
1133
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("inline-block animate-pulse", className), children });
1134
+ }
1135
+ function CompactTask({
1136
+ children,
1137
+ defaultOpen = false,
1138
+ detail,
1139
+ error,
1140
+ label,
1141
+ loading
1142
+ }) {
1143
+ const [open, setOpen] = React4.useState(defaultOpen);
1144
+ 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 });
1146
+ 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 });
1148
+ }
1149
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "w-full", children: [
1150
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1151
+ "button",
1152
+ {
1153
+ "aria-expanded": open,
1154
+ className: cn(
1155
+ "group flex min-w-0 items-center gap-1.5 rounded-md px-0 py-0.5 text-left text-sm transition-colors hover:text-foreground",
1156
+ error ? "text-destructive" : "text-muted-foreground"
1157
+ ),
1158
+ onClick: () => setOpen((value) => !value),
1159
+ type: "button",
1160
+ children: [
1161
+ 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" })
1163
+ ]
1164
+ }
1165
+ ),
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,
1168
+ children
1169
+ ] }) : null
1170
+ ] });
1171
+ }
1172
+ function ToolPartRow({
1173
+ activeToolId,
1174
+ part
1175
+ }) {
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)(
1177
+ CompactTask,
1178
+ {
1179
+ defaultOpen: part.state === "output-error",
1180
+ detail: toolDetail(part),
1181
+ error: part.state === "output-error",
1182
+ label: toolLabel(part),
1183
+ loading: isActiveTool(part, activeToolId)
1184
+ }
1185
+ ) });
1186
+ }
1187
+ function ToolGroup({
1188
+ activeToolId,
1189
+ parts
1190
+ }) {
1191
+ 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)(
1193
+ "div",
1194
+ {
1195
+ className: cn("text-sm", part.state === "output-error" ? "text-destructive" : "text-muted-foreground"),
1196
+ 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
1199
+ ]
1200
+ },
1201
+ part.id
1202
+ )) }) });
1203
+ }
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
+ function HitlPartRow({
1228
+ getHitlActionState,
1229
+ isLoading,
1230
+ onHitlAction,
1231
+ part
1232
+ }) {
1233
+ 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,
1238
+ {
1239
+ error: state?.error,
1240
+ message,
1241
+ onConnect: onHitlAction ? () => onHitlAction(part, CONNECT_DECISION) : void 0,
1242
+ serverName: mcpConnectLabel(part),
1243
+ status: normalizedMcpStatus(state?.status)
1244
+ }
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)(
1252
+ "button",
1253
+ {
1254
+ 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"
1257
+ ),
1258
+ disabled: !onHitlAction || isLoading || state?.status === "connecting" || state?.status === "resuming",
1259
+ onClick: () => onHitlAction?.(part, decision),
1260
+ type: "button",
1261
+ children: decision === "connect" ? "Connect" : decision
1262
+ },
1263
+ decision
1264
+ )) })
1265
+ ] });
1266
+ }
1267
+ function DefaultPartRow({
1268
+ activeToolId,
1269
+ getHitlActionState,
1270
+ isLoading,
1271
+ message,
1272
+ onHitlAction,
1273
+ part
1274
+ }) {
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 });
1277
+ if (part.kind === "reasoning") {
1278
+ 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 });
1280
+ }
1281
+ if (part.kind === "ui-blocks") {
1282
+ 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." });
1284
+ }
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" });
1286
+ }
1287
+ if (part.kind === "hitl") {
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1289
+ HitlPartRow,
1290
+ {
1291
+ getHitlActionState,
1292
+ isLoading,
1293
+ onHitlAction,
1294
+ part
1295
+ }
1296
+ );
1297
+ }
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 });
1300
+ return null;
1301
+ }
1302
+ function AgentResponseTimeline({
1303
+ getHitlActionState,
1304
+ isLoading = false,
1305
+ message,
1306
+ onHitlAction,
1307
+ renderPart
1308
+ }) {
1309
+ const parts = message.parts || [];
1310
+ const activeToolId = [...parts].reverse().find((part) => part.kind === "tool" && (part.state === "input-available" || part.state === "input-streaming"))?.id;
1311
+ const rendered = [];
1312
+ let index = 0;
1313
+ while (index < parts.length) {
1314
+ const part = parts[index];
1315
+ if (part.kind === "tool" && groupKey(part)) {
1316
+ const key = groupKey(part);
1317
+ const group = [];
1318
+ while (index < parts.length) {
1319
+ const candidate = parts[index];
1320
+ if (candidate.kind !== "tool" || groupKey(candidate) !== key) break;
1321
+ group.push(candidate);
1322
+ index += 1;
1323
+ }
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}`));
1325
+ continue;
1326
+ }
1327
+ rendered.push(
1328
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(React4.Fragment, { children: renderPart ? renderPart(part, message) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1329
+ DefaultPartRow,
1330
+ {
1331
+ activeToolId,
1332
+ getHitlActionState,
1333
+ isLoading,
1334
+ message,
1335
+ onHitlAction,
1336
+ part
1337
+ }
1338
+ ) }, part.id)
1339
+ );
1340
+ index += 1;
1341
+ }
1342
+ if (rendered.length === 0 && message.content) {
1343
+ rendered.push(/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageResponse, { children: message.content }, `${message.id}-fallback`));
1344
+ }
1345
+ 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`));
1347
+ }
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "space-y-3", children: rendered });
1349
+ }
1350
+
1351
+ // src/ui/agent-chat-message.tsx
1352
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1353
+ var DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD = 360;
1354
+ var DEFAULT_USER_MESSAGE_COLLAPSED_LINES = 4;
1355
+ function shouldCollapseUserMessage(content, threshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD) {
1356
+ return typeof threshold === "number" && threshold > 0 && content.length > threshold;
1357
+ }
1358
+ function AgentChatUserMessageContent({
1359
+ collapsedLines = DEFAULT_USER_MESSAGE_COLLAPSED_LINES,
1360
+ collapseThreshold = DEFAULT_USER_MESSAGE_COLLAPSE_THRESHOLD,
1361
+ content,
1362
+ showLessLabel = "Show less",
1363
+ showMoreLabel = "Show more"
1364
+ }) {
1365
+ const [isExpanded, setIsExpanded] = React5.useState(false);
1366
+ const contentId = React5.useId();
1367
+ const shouldCollapse = shouldCollapseUserMessage(content, collapseThreshold);
1368
+ const Icon = isExpanded ? import_lucide_react4.ChevronUp : import_lucide_react4.ChevronDown;
1369
+ const clampedStyle = shouldCollapse && !isExpanded ? {
1370
+ WebkitBoxOrient: "vertical",
1371
+ WebkitLineClamp: Math.max(1, collapsedLines),
1372
+ display: "-webkit-box",
1373
+ overflow: "hidden"
1374
+ } : 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)(
1378
+ "button",
1379
+ {
1380
+ "aria-controls": contentId,
1381
+ "aria-expanded": isExpanded,
1382
+ className: cn(
1383
+ "inline-flex w-fit items-center gap-1 rounded-md text-left text-sm font-medium text-muted-foreground transition-colors",
1384
+ "hover:text-foreground focus-visible:border-neutral-300 focus-visible:outline-none focus-visible:ring-0"
1385
+ ),
1386
+ onClick: () => setIsExpanded((current) => !current),
1387
+ type: "button",
1388
+ children: [
1389
+ isExpanded ? showLessLabel : showMoreLabel,
1390
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { "aria-hidden": "true", className: "size-4", strokeWidth: 2 })
1391
+ ]
1392
+ }
1393
+ ) : null
1394
+ ] });
1395
+ }
1396
+ function AgentChatMessage({
1397
+ actionHandlers,
1398
+ actions,
1399
+ actionsClassName,
1400
+ className,
1401
+ contentClassName,
1402
+ dir,
1403
+ getHitlActionState,
1404
+ message,
1405
+ onHitlAction,
1406
+ renderAssistantContent,
1407
+ renderPart,
1408
+ renderUserContent,
1409
+ showAssistantAttachments = false,
1410
+ streamingMessageId,
1411
+ userMessageCollapsedLines,
1412
+ userMessageContent,
1413
+ userMessageCollapseThreshold,
1414
+ userMessageShowLessLabel,
1415
+ userMessageShowMoreLabel
1416
+ }) {
1417
+ const isAssistant = message.role === "assistant";
1418
+ const isStreaming = isAssistant && message.id === streamingMessageId;
1419
+ const resolvedUserContent = userMessageContent ?? message.content;
1420
+ const shouldRenderContent = isAssistant || Boolean(renderUserContent || resolvedUserContent);
1421
+ 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)(
1425
+ ChatAttachment,
1426
+ {
1427
+ data: attachment,
1428
+ dir: "ltr"
1429
+ },
1430
+ String(attachment.url || attachment.filename || index)
1431
+ )) }) : null,
1432
+ shouldRenderContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1433
+ ChatMessageContent,
1434
+ {
1435
+ className: cn(isAssistant ? "bg-transparent p-0" : void 0, contentClassName),
1436
+ dir,
1437
+ children: [
1438
+ isAssistant ? renderAssistantContent ? renderAssistantContent({ isStreaming, message }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1439
+ AgentResponseTimeline,
1440
+ {
1441
+ getHitlActionState,
1442
+ isLoading: isStreaming,
1443
+ message,
1444
+ onHitlAction,
1445
+ renderPart
1446
+ }
1447
+ ) : null,
1448
+ !isAssistant ? renderUserContent ? renderUserContent({ message }) : resolvedUserContent ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1449
+ AgentChatUserMessageContent,
1450
+ {
1451
+ collapsedLines: userMessageCollapsedLines,
1452
+ collapseThreshold: userMessageCollapseThreshold,
1453
+ content: resolvedUserContent,
1454
+ showLessLabel: userMessageShowLessLabel,
1455
+ showMoreLabel: userMessageShowMoreLabel
1456
+ }
1457
+ ) : null : null
1458
+ ]
1459
+ }
1460
+ ) : 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
1462
+ ] });
1463
+ }
1464
+
1465
+ // src/ui/bubble.tsx
1466
+ var import_class_variance_authority2 = require("class-variance-authority");
1467
+ var import_react_slot2 = require("@radix-ui/react-slot");
1468
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1469
+ function BubbleGroup({ className, ...props }) {
1470
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1471
+ "div",
1472
+ {
1473
+ "data-slot": "bubble-group",
1474
+ className: cn("flex min-w-0 flex-col gap-2", className),
1475
+ ...props
1476
+ }
1477
+ );
1478
+ }
1479
+ var bubbleVariants = (0, import_class_variance_authority2.cva)(
1480
+ "group/bubble relative flex w-fit max-w-[80%] min-w-0 flex-col gap-1 group-data-[align=end]/message:self-end data-[align=end]:self-end data-[variant=ghost]:max-w-full",
1481
+ {
1482
+ variants: {
1483
+ variant: {
1484
+ default: "*:data-[slot=bubble-content]:bg-neutral-900 *:data-[slot=bubble-content]:text-white [&>[data-slot=bubble-content]:is(button,a):hover]:bg-neutral-800",
1485
+ secondary: "*:data-[slot=bubble-content]:bg-muted *:data-[slot=bubble-content]:text-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted",
1486
+ muted: "*:data-[slot=bubble-content]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:bg-[color-mix(in_oklch,var(--muted),var(--foreground)_5%)]",
1487
+ tinted: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-muted *:data-[slot=bubble-content]:text-foreground [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted",
1488
+ outline: "*:data-[slot=bubble-content]:border-border *:data-[slot=bubble-content]:bg-background [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-input/30",
1489
+ ghost: "border-none *:data-[slot=bubble-content]:rounded-none *:data-[slot=bubble-content]:bg-transparent *:data-[slot=bubble-content]:p-0 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted [&>[data-slot=bubble-content]:is(button,a):hover]:text-foreground dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-muted/50",
1490
+ destructive: "*:data-[slot=bubble-content]:bg-destructive/10 *:data-[slot=bubble-content]:text-destructive dark:*:data-[slot=bubble-content]:bg-destructive/20 [&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/20 dark:[&>[data-slot=bubble-content]:is(button,a):hover]:bg-destructive/30"
1491
+ }
1492
+ },
1493
+ defaultVariants: {
1494
+ variant: "default"
1495
+ }
1496
+ }
1497
+ );
1498
+ function Bubble({
1499
+ variant = "default",
1500
+ align = "start",
1501
+ className,
1502
+ ...props
1503
+ }) {
1504
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1505
+ "div",
1506
+ {
1507
+ "data-slot": "bubble",
1508
+ "data-variant": variant,
1509
+ "data-align": align,
1510
+ className: cn(bubbleVariants({ variant }), className),
1511
+ ...props
1512
+ }
1513
+ );
1514
+ }
1515
+ function BubbleContent({
1516
+ asChild = false,
1517
+ className,
1518
+ ...props
1519
+ }) {
1520
+ const Comp = asChild ? import_react_slot2.Slot : "div";
1521
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1522
+ Comp,
1523
+ {
1524
+ "data-slot": "bubble-content",
1525
+ className: cn(
1526
+ "w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-neutral-300 [button,a]:focus-visible:ring-0",
1527
+ className
1528
+ ),
1529
+ ...props
1530
+ }
1531
+ );
1532
+ }
1533
+ var bubbleReactionsVariants = (0, import_class_variance_authority2.cva)(
1534
+ "absolute z-10 flex w-fit shrink-0 items-center justify-center gap-1 rounded-full bg-muted px-1.5 py-0.5 text-sm ring-3 ring-card has-[button]:p-0",
1535
+ {
1536
+ variants: {
1537
+ side: {
1538
+ top: "top-0 -translate-y-3/4",
1539
+ bottom: "bottom-0 translate-y-3/4"
1540
+ },
1541
+ align: {
1542
+ start: "left-3",
1543
+ end: "right-3"
1544
+ }
1545
+ },
1546
+ defaultVariants: {
1547
+ side: "bottom",
1548
+ align: "end"
1549
+ }
1550
+ }
1551
+ );
1552
+ function BubbleReactions({
1553
+ side = "bottom",
1554
+ align = "end",
1555
+ className,
1556
+ ...props
1557
+ }) {
1558
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1559
+ "div",
1560
+ {
1561
+ "data-slot": "bubble-reactions",
1562
+ "data-align": align,
1563
+ "data-side": side,
1564
+ className: cn(bubbleReactionsVariants({ side, align }), className),
1565
+ ...props
1566
+ }
1567
+ );
1568
+ }
1569
+
1570
+ // src/ui/marker.tsx
1571
+ var import_class_variance_authority3 = require("class-variance-authority");
1572
+ var import_react_slot3 = require("@radix-ui/react-slot");
1573
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1574
+ var markerVariants = (0, import_class_variance_authority3.cva)(
1575
+ "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
+ {
1577
+ variants: {
1578
+ variant: {
1579
+ default: "",
1580
+ separator: "before:mr-1 before:h-px before:min-w-0 before:flex-1 before:bg-border after:ml-1 after:h-px after:min-w-0 after:flex-1 after:bg-border",
1581
+ border: "border-b border-border pb-2"
1582
+ }
1583
+ }
1584
+ }
1585
+ );
1586
+ function Marker({
1587
+ className,
1588
+ variant = "default",
1589
+ asChild = false,
1590
+ ...props
1591
+ }) {
1592
+ const Comp = asChild ? import_react_slot3.Slot : "div";
1593
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1594
+ Comp,
1595
+ {
1596
+ "data-slot": "marker",
1597
+ "data-variant": variant,
1598
+ className: cn(markerVariants({ variant, className })),
1599
+ ...props
1600
+ }
1601
+ );
1602
+ }
1603
+ function MarkerIcon({ className, ...props }) {
1604
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1605
+ "span",
1606
+ {
1607
+ "data-slot": "marker-icon",
1608
+ "aria-hidden": "true",
1609
+ className: cn(
1610
+ "size-4 shrink-0 [&_svg:not([class*='size-'])]:size-4",
1611
+ className
1612
+ ),
1613
+ ...props
1614
+ }
1615
+ );
1616
+ }
1617
+ function MarkerContent({ className, ...props }) {
1618
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1619
+ "span",
1620
+ {
1621
+ "data-slot": "marker-content",
1622
+ className: cn(
1623
+ "min-w-0 wrap-break-word group-data-[variant=separator]/marker:flex-none group-data-[variant=separator]/marker:text-center *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
1624
+ className
1625
+ ),
1626
+ ...props
1627
+ }
1628
+ );
1629
+ }
900
1630
  // Annotate the CommonJS export names for ESM import in node:
901
1631
  0 && (module.exports = {
1632
+ AgentChatComposer,
1633
+ AgentChatDefaultActions,
1634
+ AgentChatMessage,
1635
+ AgentChatPartRow,
1636
+ AgentChatUserMessageContent,
1637
+ AgentResponseTimeline,
902
1638
  Attachment,
903
1639
  AttachmentAction,
904
1640
  AttachmentActions,
@@ -921,6 +1657,7 @@ MessageResponse.displayName = "MessageResponse";
921
1657
  Marker,
922
1658
  MarkerContent,
923
1659
  MarkerIcon,
1660
+ McpConnectRequiredCard,
924
1661
  Message,
925
1662
  MessageAction,
926
1663
  MessageActions,
@@ -938,6 +1675,7 @@ MessageResponse.displayName = "MessageResponse";
938
1675
  attachmentVariants,
939
1676
  bubbleVariants,
940
1677
  cn,
941
- markerVariants
1678
+ markerVariants,
1679
+ shouldCollapseUserMessage
942
1680
  });
943
1681
  //# sourceMappingURL=index.cjs.map