@agents24/chat-react 0.1.8 → 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/README.md +16 -4
- package/dist/controller-actions.d.ts +45 -0
- package/dist/controller-helpers.d.ts +27 -0
- package/dist/controller.d.ts +2 -7
- package/dist/index.cjs +568 -207
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +511 -157
- package/dist/index.js.map +1 -1
- package/dist/message-lifecycle.d.ts +15 -0
- package/dist/model.d.ts +2 -0
- package/dist/renderers.d.ts +1 -1
- package/dist/sse.d.ts +3 -1
- package/dist/templates/agent-chat-shell.d.ts +13 -1
- package/dist/templates/index.cjs +90 -24
- package/dist/templates/index.cjs.map +1 -1
- package/dist/templates/index.js +88 -23
- package/dist/templates/index.js.map +1 -1
- package/dist/transport.d.ts +14 -0
- package/dist/types.d.ts +61 -4
- package/dist/ui/adapters.d.ts +1 -2
- package/dist/ui/agent-chat-actions.d.ts +16 -0
- package/dist/ui/agent-chat-composer.d.ts +28 -0
- package/dist/ui/agent-chat-message.d.ts +40 -0
- package/dist/ui/agent-response-timeline.d.ts +24 -0
- package/dist/ui/index.cjs +944 -206
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.js +932 -202
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/mcp-connect-required-card.d.ts +13 -0
- package/package.json +2 -1
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/
|
|
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/
|
|
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:
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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:
|
|
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,
|
|
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,
|
|
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
|
|
468
|
-
isUser ? cn("is-user
|
|
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
|
|
619
|
+
return React2.createElement(Message, messageProps);
|
|
472
620
|
}
|
|
473
621
|
function ChatMessageContent({
|
|
474
622
|
className,
|
|
475
623
|
...props
|
|
476
624
|
}) {
|
|
477
|
-
return
|
|
625
|
+
return React2.createElement("div", {
|
|
478
626
|
className: cn(
|
|
479
|
-
"flex w-
|
|
480
|
-
"group-[.is-user]:
|
|
481
|
-
"group-[.is-assistant]:w-full group-[.is-assistant]:max-w-full group-[.is-assistant]:
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
|
685
|
+
return React2.createElement(
|
|
538
686
|
Attachment,
|
|
539
687
|
{
|
|
540
688
|
orientation: orientation || (isImage ? "vertical" : "horizontal"),
|
|
541
689
|
...props
|
|
542
690
|
},
|
|
543
|
-
|
|
691
|
+
React2.createElement(
|
|
544
692
|
AttachmentMedia,
|
|
545
693
|
{ variant: isImage ? "image" : "icon" },
|
|
546
|
-
isImage ?
|
|
694
|
+
isImage ? React2.createElement("img", {
|
|
547
695
|
alt: filename,
|
|
548
696
|
className: "size-full object-cover",
|
|
549
697
|
src: data.url
|
|
550
|
-
}) :
|
|
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
|
-
|
|
704
|
+
React2.createElement(
|
|
557
705
|
AttachmentContent,
|
|
558
706
|
null,
|
|
559
|
-
|
|
560
|
-
|
|
707
|
+
React2.createElement(AttachmentTitle, null, filename),
|
|
708
|
+
React2.createElement(AttachmentDescription, null, mediaType)
|
|
561
709
|
),
|
|
562
|
-
onRemove ?
|
|
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
|
-
|
|
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
|
|
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/
|
|
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
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
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
|
-
|
|
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
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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-
|
|
828
|
+
"data-agents24-mcp-connect-card": true,
|
|
829
|
+
"data-status": status,
|
|
649
830
|
className: cn(
|
|
650
|
-
"
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
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 =
|
|
1031
|
+
const childArray = React3.Children.toArray(children).filter(
|
|
831
1032
|
(child) => child !== null && child !== ""
|
|
832
1033
|
);
|
|
833
|
-
const isImageOnly = childArray.length === 1 &&
|
|
1034
|
+
const isImageOnly = childArray.length === 1 && React3.isValidElement(childArray[0]) && childArray[0].props.node?.tagName === "img";
|
|
834
1035
|
if (isImageOnly) {
|
|
835
|
-
return /* @__PURE__ */ (0,
|
|
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,
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ...domProps, children });
|
|
839
1040
|
}
|
|
840
|
-
return /* @__PURE__ */ (0,
|
|
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 =
|
|
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 =
|
|
1083
|
+
const streamdownComponents = React3.useMemo(
|
|
883
1084
|
() => ({ ...MESSAGE_RESPONSE_COMPONENTS, ...components }),
|
|
884
1085
|
[components]
|
|
885
1086
|
);
|
|
886
|
-
return /* @__PURE__ */ (0,
|
|
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
|