@agents24/chat-react 0.5.4 → 0.5.6
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 +8 -2
- package/compatibility.json +4 -4
- package/dist/runtime/index.cjs +127 -18
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.js +125 -18
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/use-agent-chat-runtime.d.ts +17 -2
- package/dist/scaffold/app.d.ts +1 -0
- package/dist/scaffold/components/chat/chat-composer.d.ts +10 -2
- package/dist/scaffold/components/chat/chat-message.d.ts +3 -1
- package/dist/scaffold/components/chat/chat-shell.d.ts +3 -1
- package/dist/scaffold/index.cjs +415 -253
- package/dist/scaffold/index.cjs.map +1 -1
- package/dist/scaffold/index.js +408 -240
- package/dist/scaffold/index.js.map +1 -1
- package/dist/styles.css +18 -4
- package/dist/ui/adapters.d.ts +14 -2
- package/dist/ui/agent-chat-composer.d.ts +2 -9
- package/dist/ui/agent-chat-message.d.ts +3 -1
- package/dist/ui/composer-attachments.d.ts +11 -0
- package/dist/ui/index.cjs +653 -343
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +638 -328
- package/dist/ui/index.js.map +1 -1
- package/package.json +4 -3
- package/scaffold/src/app.tsx +2 -1
- package/scaffold/src/chat.css +13 -1
- package/scaffold/src/components/chat/chat-composer.tsx +107 -27
- package/scaffold/src/components/chat/chat-message.tsx +8 -9
- package/scaffold/src/components/chat/chat-shell.tsx +24 -11
- package/scaffold/src/components/ui/button.tsx +1 -1
- package/scaffold/src/components/ui/dropdown-menu.tsx +1 -1
- package/scaffold/src/components/ui/sidebar.tsx +4 -4
package/dist/ui/index.js
CHANGED
|
@@ -4,8 +4,21 @@ import {
|
|
|
4
4
|
} from "../chunk-SSUO4EPD.js";
|
|
5
5
|
|
|
6
6
|
// src/ui/agent-chat-composer.tsx
|
|
7
|
+
import * as React2 from "react";
|
|
8
|
+
import { ArrowUp, Plus, Square } from "lucide-react";
|
|
9
|
+
|
|
10
|
+
// src/ui/adapters.ts
|
|
7
11
|
import * as React from "react";
|
|
8
|
-
import {
|
|
12
|
+
import { FileIcon } from "@untitledui/file-icons";
|
|
13
|
+
import {
|
|
14
|
+
ImageOff,
|
|
15
|
+
LoaderCircle,
|
|
16
|
+
X
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
|
|
19
|
+
// src/ui/attachment.tsx
|
|
20
|
+
import { cva } from "class-variance-authority";
|
|
21
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
9
22
|
|
|
10
23
|
// src/ui/utils.ts
|
|
11
24
|
import { clsx } from "clsx";
|
|
@@ -14,266 +27,8 @@ function cn(...values) {
|
|
|
14
27
|
return twMerge(clsx(values));
|
|
15
28
|
}
|
|
16
29
|
|
|
17
|
-
// src/ui/agent-chat-composer.tsx
|
|
18
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
-
var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
20
|
-
function createComposerFile(file) {
|
|
21
|
-
return {
|
|
22
|
-
id: createId(),
|
|
23
|
-
type: "file",
|
|
24
|
-
url: URL.createObjectURL(file),
|
|
25
|
-
filename: file.name || "attachment",
|
|
26
|
-
mediaType: file.type || "application/octet-stream",
|
|
27
|
-
source: file
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function revokeComposerFiles(files) {
|
|
31
|
-
files.forEach((file) => {
|
|
32
|
-
try {
|
|
33
|
-
URL.revokeObjectURL(file.url);
|
|
34
|
-
} catch {
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
function formatFileCount(files) {
|
|
39
|
-
if (files.length === 1) return files[0].filename;
|
|
40
|
-
return `${files.length} files`;
|
|
41
|
-
}
|
|
42
|
-
var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-muted text-sm text-muted-foreground shadow-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
43
|
-
var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-primary text-sm text-primary-foreground shadow-none transition-[background-color,color,opacity,transform] duration-200 hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
44
|
-
function AgentChatComposer({
|
|
45
|
-
accept,
|
|
46
|
-
allowAttachments = true,
|
|
47
|
-
attachmentLayout = "flow",
|
|
48
|
-
className,
|
|
49
|
-
disabled = false,
|
|
50
|
-
forceExpanded = false,
|
|
51
|
-
inputToolbarContent,
|
|
52
|
-
isRunning = false,
|
|
53
|
-
onAttachmentCountChange,
|
|
54
|
-
onStop,
|
|
55
|
-
onSubmit,
|
|
56
|
-
placeholder = "Message the agent",
|
|
57
|
-
textareaRef
|
|
58
|
-
}) {
|
|
59
|
-
const fileInputRef = React.useRef(null);
|
|
60
|
-
const filesRef = React.useRef([]);
|
|
61
|
-
const localTextareaRef = React.useRef(null);
|
|
62
|
-
const [text, setText] = React.useState("");
|
|
63
|
-
const [files, setFiles] = React.useState([]);
|
|
64
|
-
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
65
|
-
const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
|
|
66
|
-
const setTextareaRef = React.useCallback(
|
|
67
|
-
(node) => {
|
|
68
|
-
localTextareaRef.current = node;
|
|
69
|
-
if (typeof textareaRef === "function") {
|
|
70
|
-
textareaRef(node);
|
|
71
|
-
} else if (textareaRef) {
|
|
72
|
-
textareaRef.current = node;
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
[textareaRef]
|
|
76
|
-
);
|
|
77
|
-
React.useEffect(() => {
|
|
78
|
-
filesRef.current = files;
|
|
79
|
-
onAttachmentCountChange?.(files.length);
|
|
80
|
-
}, [files, onAttachmentCountChange]);
|
|
81
|
-
React.useEffect(() => () => revokeComposerFiles(filesRef.current), []);
|
|
82
|
-
React.useLayoutEffect(() => {
|
|
83
|
-
const textarea = localTextareaRef.current;
|
|
84
|
-
if (!textarea) return;
|
|
85
|
-
if (isExpanded) {
|
|
86
|
-
textarea.style.height = "auto";
|
|
87
|
-
const scrollHeight = textarea.scrollHeight;
|
|
88
|
-
textarea.style.height = `${Math.min(scrollHeight, 224)}px`;
|
|
89
|
-
textarea.style.overflowY = scrollHeight >= 224 ? "auto" : "hidden";
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
textarea.style.height = "";
|
|
93
|
-
textarea.style.overflowY = "hidden";
|
|
94
|
-
}, [isExpanded, text]);
|
|
95
|
-
const canSubmit = !disabled && !isSubmitting && !isRunning && (text.trim().length > 0 || files.length > 0);
|
|
96
|
-
const handleFilesChange = (event) => {
|
|
97
|
-
const selected = Array.from(event.target.files || []).map(createComposerFile);
|
|
98
|
-
if (selected.length > 0) {
|
|
99
|
-
setFiles((current) => [...current, ...selected]);
|
|
100
|
-
}
|
|
101
|
-
event.currentTarget.value = "";
|
|
102
|
-
};
|
|
103
|
-
const removeFile = (fileId) => {
|
|
104
|
-
setFiles((current) => {
|
|
105
|
-
const target = current.find((file) => file.id === fileId);
|
|
106
|
-
if (target) revokeComposerFiles([target]);
|
|
107
|
-
return current.filter((file) => file.id !== fileId);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
const submit = async () => {
|
|
111
|
-
if (!canSubmit) return;
|
|
112
|
-
const submittedText = text.trim();
|
|
113
|
-
const submittedFiles = files;
|
|
114
|
-
setIsSubmitting(true);
|
|
115
|
-
try {
|
|
116
|
-
await onSubmit({ text: submittedText, files: submittedFiles });
|
|
117
|
-
setText("");
|
|
118
|
-
setFiles([]);
|
|
119
|
-
revokeComposerFiles(submittedFiles);
|
|
120
|
-
} catch {
|
|
121
|
-
} finally {
|
|
122
|
-
setIsSubmitting(false);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
const handleKeyDown = (event) => {
|
|
126
|
-
if (event.key === "Enter" && !event.shiftKey) {
|
|
127
|
-
event.preventDefault();
|
|
128
|
-
void submit();
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
|
|
132
|
-
files.length > 0 ? /* @__PURE__ */ jsx(
|
|
133
|
-
"div",
|
|
134
|
-
{
|
|
135
|
-
"data-testid": "agent-chat-composer-attachments",
|
|
136
|
-
"data-layout": attachmentLayout,
|
|
137
|
-
className: cn(
|
|
138
|
-
"a24-composer__attachments flex min-w-0 gap-2 py-1",
|
|
139
|
-
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"
|
|
140
|
-
),
|
|
141
|
-
children: files.map((file) => /* @__PURE__ */ jsxs(
|
|
142
|
-
"div",
|
|
143
|
-
{
|
|
144
|
-
className: "a24-composer__attachment 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-border bg-card px-1.5 text-sm font-medium text-card-foreground transition-colors hover:bg-accent",
|
|
145
|
-
children: [
|
|
146
|
-
/* @__PURE__ */ jsx("span", { className: "flex size-5 shrink-0 items-center justify-center rounded bg-background text-muted-foreground", children: /* @__PURE__ */ jsx(Paperclip, { className: "size-3" }) }),
|
|
147
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: file.filename }),
|
|
148
|
-
/* @__PURE__ */ jsx(
|
|
149
|
-
"button",
|
|
150
|
-
{
|
|
151
|
-
"aria-label": `Remove ${file.filename}`,
|
|
152
|
-
className: "a24-composer__attachment-remove 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",
|
|
153
|
-
onClick: () => removeFile(file.id),
|
|
154
|
-
type: "button",
|
|
155
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-3" })
|
|
156
|
-
}
|
|
157
|
-
)
|
|
158
|
-
]
|
|
159
|
-
},
|
|
160
|
-
file.id
|
|
161
|
-
))
|
|
162
|
-
}
|
|
163
|
-
) : null,
|
|
164
|
-
/* @__PURE__ */ jsx(
|
|
165
|
-
"div",
|
|
166
|
-
{
|
|
167
|
-
"data-expanded": isExpanded ? "" : void 0,
|
|
168
|
-
className: cn(
|
|
169
|
-
"a24-composer__surface relative w-full border border-input bg-background shadow-sm",
|
|
170
|
-
isExpanded ? "rounded-xl p-2 pb-1.5" : "rounded-xl px-2 py-[3px]"
|
|
171
|
-
),
|
|
172
|
-
children: /* @__PURE__ */ jsxs(
|
|
173
|
-
"div",
|
|
174
|
-
{
|
|
175
|
-
className: "a24-composer__grid w-full",
|
|
176
|
-
style: {
|
|
177
|
-
alignItems: "center",
|
|
178
|
-
display: "grid",
|
|
179
|
-
gridTemplateAreas: isExpanded ? `"textarea textarea textarea" "plus toolbar submit"` : `"plus textarea composer mic submit"`,
|
|
180
|
-
gridTemplateColumns: isExpanded ? "auto 1fr auto" : "auto 1fr auto auto auto",
|
|
181
|
-
gap: isExpanded ? "3px 10px" : "8px"
|
|
182
|
-
},
|
|
183
|
-
children: [
|
|
184
|
-
/* @__PURE__ */ jsxs("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
|
|
185
|
-
/* @__PURE__ */ jsx(
|
|
186
|
-
"input",
|
|
187
|
-
{
|
|
188
|
-
ref: fileInputRef,
|
|
189
|
-
accept,
|
|
190
|
-
"aria-label": "Attach files",
|
|
191
|
-
className: "hidden",
|
|
192
|
-
multiple: true,
|
|
193
|
-
name: "attachments",
|
|
194
|
-
onChange: handleFilesChange,
|
|
195
|
-
type: "file"
|
|
196
|
-
}
|
|
197
|
-
),
|
|
198
|
-
/* @__PURE__ */ jsx(
|
|
199
|
-
"button",
|
|
200
|
-
{
|
|
201
|
-
"aria-label": "Attach files",
|
|
202
|
-
className: cn("a24-composer__attach", pillButtonClass),
|
|
203
|
-
disabled: disabled || isSubmitting || isRunning || !allowAttachments,
|
|
204
|
-
onClick: () => fileInputRef.current?.click(),
|
|
205
|
-
title: "Attach files",
|
|
206
|
-
type: "button",
|
|
207
|
-
children: /* @__PURE__ */ jsx(Plus, { className: "size-4" })
|
|
208
|
-
}
|
|
209
|
-
)
|
|
210
|
-
] }),
|
|
211
|
-
/* @__PURE__ */ jsx("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ jsx(
|
|
212
|
-
"textarea",
|
|
213
|
-
{
|
|
214
|
-
ref: setTextareaRef,
|
|
215
|
-
"aria-label": "Message",
|
|
216
|
-
autoComplete: "off",
|
|
217
|
-
className: cn(
|
|
218
|
-
"a24-composer__textarea w-full resize-none border-0 bg-transparent px-1 text-[15px] leading-relaxed text-foreground shadow-none outline-none placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
|
|
219
|
-
isExpanded ? "min-h-9 max-h-[224px] py-1" : "min-h-9 h-9 max-h-9 py-2"
|
|
220
|
-
),
|
|
221
|
-
disabled: disabled || isSubmitting || isRunning,
|
|
222
|
-
name: "message",
|
|
223
|
-
onChange: (event) => setText(event.target.value),
|
|
224
|
-
onKeyDown: handleKeyDown,
|
|
225
|
-
placeholder,
|
|
226
|
-
rows: isExpanded ? 2 : 1,
|
|
227
|
-
value: text
|
|
228
|
-
}
|
|
229
|
-
) }),
|
|
230
|
-
isExpanded ? /* @__PURE__ */ jsx("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: inputToolbarContent }) : null,
|
|
231
|
-
!isExpanded ? /* @__PURE__ */ jsx("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
|
|
232
|
-
!isExpanded ? /* @__PURE__ */ jsx("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end" }) : null,
|
|
233
|
-
/* @__PURE__ */ jsx("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end", children: isRunning ? /* @__PURE__ */ jsx(
|
|
234
|
-
"button",
|
|
235
|
-
{
|
|
236
|
-
"aria-label": "Stop generating",
|
|
237
|
-
className: cn("a24-composer__submit", submitButtonClass),
|
|
238
|
-
disabled: disabled || !onStop,
|
|
239
|
-
onClick: onStop,
|
|
240
|
-
title: "Stop",
|
|
241
|
-
type: "button",
|
|
242
|
-
children: /* @__PURE__ */ jsx(Square, { className: "size-3.5 fill-current" })
|
|
243
|
-
}
|
|
244
|
-
) : /* @__PURE__ */ jsx(
|
|
245
|
-
"button",
|
|
246
|
-
{
|
|
247
|
-
"aria-label": files.length > 0 ? `Send ${formatFileCount(files)}` : "Send message",
|
|
248
|
-
className: cn("a24-composer__submit", submitButtonClass, text.trim().length > 0 && "hover:scale-105"),
|
|
249
|
-
disabled: !canSubmit,
|
|
250
|
-
onClick: () => void submit(),
|
|
251
|
-
title: "Send",
|
|
252
|
-
type: "button",
|
|
253
|
-
children: /* @__PURE__ */ jsx(ArrowUp, { className: "size-4", strokeWidth: 2.5 })
|
|
254
|
-
}
|
|
255
|
-
) })
|
|
256
|
-
]
|
|
257
|
-
}
|
|
258
|
-
)
|
|
259
|
-
}
|
|
260
|
-
),
|
|
261
|
-
!isExpanded && inputToolbarContent ? /* @__PURE__ */ jsx("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
|
|
262
|
-
] });
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// src/ui/agent-chat-actions.tsx
|
|
266
|
-
import * as React3 from "react";
|
|
267
|
-
import { Check, Copy, RefreshCcw, ThumbsDown, ThumbsUp } from "lucide-react";
|
|
268
|
-
import { Popover } from "radix-ui";
|
|
269
|
-
|
|
270
|
-
// src/ui/adapters.ts
|
|
271
|
-
import * as React2 from "react";
|
|
272
|
-
|
|
273
30
|
// src/ui/attachment.tsx
|
|
274
|
-
import {
|
|
275
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
276
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
31
|
+
import { jsx } from "react/jsx-runtime";
|
|
277
32
|
var attachmentVariants = cva(
|
|
278
33
|
"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",
|
|
279
34
|
{
|
|
@@ -297,7 +52,7 @@ function Attachment({
|
|
|
297
52
|
orientation = "horizontal",
|
|
298
53
|
...props
|
|
299
54
|
}) {
|
|
300
|
-
return /* @__PURE__ */
|
|
55
|
+
return /* @__PURE__ */ jsx(
|
|
301
56
|
"div",
|
|
302
57
|
{
|
|
303
58
|
"data-slot": "attachment",
|
|
@@ -310,12 +65,12 @@ function Attachment({
|
|
|
310
65
|
);
|
|
311
66
|
}
|
|
312
67
|
var attachmentMediaVariants = cva(
|
|
313
|
-
"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg
|
|
68
|
+
"relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg text-foreground group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[state=error]/attachment:text-destructive group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5",
|
|
314
69
|
{
|
|
315
70
|
variants: {
|
|
316
71
|
variant: {
|
|
317
72
|
icon: "",
|
|
318
|
-
image: "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
|
|
73
|
+
image: "bg-muted opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
|
|
319
74
|
}
|
|
320
75
|
},
|
|
321
76
|
defaultVariants: {
|
|
@@ -328,7 +83,7 @@ function AttachmentMedia({
|
|
|
328
83
|
variant = "icon",
|
|
329
84
|
...props
|
|
330
85
|
}) {
|
|
331
|
-
return /* @__PURE__ */
|
|
86
|
+
return /* @__PURE__ */ jsx(
|
|
332
87
|
"div",
|
|
333
88
|
{
|
|
334
89
|
"data-slot": "attachment-media",
|
|
@@ -342,7 +97,7 @@ function AttachmentContent({
|
|
|
342
97
|
className,
|
|
343
98
|
...props
|
|
344
99
|
}) {
|
|
345
|
-
return /* @__PURE__ */
|
|
100
|
+
return /* @__PURE__ */ jsx(
|
|
346
101
|
"div",
|
|
347
102
|
{
|
|
348
103
|
"data-slot": "attachment-content",
|
|
@@ -358,7 +113,7 @@ function AttachmentTitle({
|
|
|
358
113
|
className,
|
|
359
114
|
...props
|
|
360
115
|
}) {
|
|
361
|
-
return /* @__PURE__ */
|
|
116
|
+
return /* @__PURE__ */ jsx(
|
|
362
117
|
"span",
|
|
363
118
|
{
|
|
364
119
|
"data-slot": "attachment-title",
|
|
@@ -374,7 +129,7 @@ function AttachmentDescription({
|
|
|
374
129
|
className,
|
|
375
130
|
...props
|
|
376
131
|
}) {
|
|
377
|
-
return /* @__PURE__ */
|
|
132
|
+
return /* @__PURE__ */ jsx(
|
|
378
133
|
"span",
|
|
379
134
|
{
|
|
380
135
|
"data-slot": "attachment-description",
|
|
@@ -391,7 +146,7 @@ function AttachmentActions({
|
|
|
391
146
|
className,
|
|
392
147
|
...props
|
|
393
148
|
}) {
|
|
394
|
-
return /* @__PURE__ */
|
|
149
|
+
return /* @__PURE__ */ jsx(
|
|
395
150
|
"div",
|
|
396
151
|
{
|
|
397
152
|
"data-slot": "attachment-actions",
|
|
@@ -408,7 +163,7 @@ function AttachmentAction({
|
|
|
408
163
|
type = "button",
|
|
409
164
|
...props
|
|
410
165
|
}) {
|
|
411
|
-
return /* @__PURE__ */
|
|
166
|
+
return /* @__PURE__ */ jsx(
|
|
412
167
|
"button",
|
|
413
168
|
{
|
|
414
169
|
"data-slot": "attachment-action",
|
|
@@ -428,7 +183,7 @@ function AttachmentTrigger({
|
|
|
428
183
|
...props
|
|
429
184
|
}) {
|
|
430
185
|
const Comp = asChild ? Slot : "button";
|
|
431
|
-
return /* @__PURE__ */
|
|
186
|
+
return /* @__PURE__ */ jsx(
|
|
432
187
|
Comp,
|
|
433
188
|
{
|
|
434
189
|
"data-slot": "attachment-trigger",
|
|
@@ -439,7 +194,7 @@ function AttachmentTrigger({
|
|
|
439
194
|
);
|
|
440
195
|
}
|
|
441
196
|
function AttachmentGroup({ className, ...props }) {
|
|
442
|
-
return /* @__PURE__ */
|
|
197
|
+
return /* @__PURE__ */ jsx(
|
|
443
198
|
"div",
|
|
444
199
|
{
|
|
445
200
|
"data-slot": "attachment-group",
|
|
@@ -453,9 +208,9 @@ function AttachmentGroup({ className, ...props }) {
|
|
|
453
208
|
}
|
|
454
209
|
|
|
455
210
|
// src/ui/message.tsx
|
|
456
|
-
import { jsx as
|
|
211
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
457
212
|
function MessageGroup({ className, ...props }) {
|
|
458
|
-
return /* @__PURE__ */
|
|
213
|
+
return /* @__PURE__ */ jsx2(
|
|
459
214
|
"div",
|
|
460
215
|
{
|
|
461
216
|
"data-slot": "message-group",
|
|
@@ -469,7 +224,7 @@ function Message({
|
|
|
469
224
|
align = "start",
|
|
470
225
|
...props
|
|
471
226
|
}) {
|
|
472
|
-
return /* @__PURE__ */
|
|
227
|
+
return /* @__PURE__ */ jsx2(
|
|
473
228
|
"div",
|
|
474
229
|
{
|
|
475
230
|
"data-slot": "message",
|
|
@@ -483,7 +238,7 @@ function Message({
|
|
|
483
238
|
);
|
|
484
239
|
}
|
|
485
240
|
function MessageAvatar({ className, ...props }) {
|
|
486
|
-
return /* @__PURE__ */
|
|
241
|
+
return /* @__PURE__ */ jsx2(
|
|
487
242
|
"div",
|
|
488
243
|
{
|
|
489
244
|
"data-slot": "message-avatar",
|
|
@@ -496,7 +251,7 @@ function MessageAvatar({ className, ...props }) {
|
|
|
496
251
|
);
|
|
497
252
|
}
|
|
498
253
|
function MessageContent({ className, ...props }) {
|
|
499
|
-
return /* @__PURE__ */
|
|
254
|
+
return /* @__PURE__ */ jsx2(
|
|
500
255
|
"div",
|
|
501
256
|
{
|
|
502
257
|
"data-slot": "message-content",
|
|
@@ -509,7 +264,7 @@ function MessageContent({ className, ...props }) {
|
|
|
509
264
|
);
|
|
510
265
|
}
|
|
511
266
|
function MessageHeader({ className, ...props }) {
|
|
512
|
-
return /* @__PURE__ */
|
|
267
|
+
return /* @__PURE__ */ jsx2(
|
|
513
268
|
"div",
|
|
514
269
|
{
|
|
515
270
|
"data-slot": "message-header",
|
|
@@ -522,7 +277,7 @@ function MessageHeader({ className, ...props }) {
|
|
|
522
277
|
);
|
|
523
278
|
}
|
|
524
279
|
function MessageFooter({ className, ...props }) {
|
|
525
|
-
return /* @__PURE__ */
|
|
280
|
+
return /* @__PURE__ */ jsx2(
|
|
526
281
|
"div",
|
|
527
282
|
{
|
|
528
283
|
"data-slot": "message-footer",
|
|
@@ -536,23 +291,22 @@ function MessageFooter({ className, ...props }) {
|
|
|
536
291
|
}
|
|
537
292
|
|
|
538
293
|
// src/ui/adapters.ts
|
|
539
|
-
var ChatMessageRoleContext =
|
|
294
|
+
var ChatMessageRoleContext = React.createContext("assistant");
|
|
540
295
|
function ChatMessage(input) {
|
|
541
296
|
const { className, from, align, ...props } = input;
|
|
542
297
|
const isUser = from === "user";
|
|
543
|
-
const isRtl = props.dir === "rtl";
|
|
544
298
|
const resolvedAlign = align || "start";
|
|
545
299
|
const messageProps = Object.assign({}, props);
|
|
546
300
|
messageProps.align = resolvedAlign;
|
|
547
301
|
messageProps.className = cn(
|
|
548
302
|
"a24-chat-message group flex w-full flex-col gap-2",
|
|
549
|
-
isUser ?
|
|
303
|
+
isUser ? "a24-chat-message--user is-user max-w-full justify-end" : "a24-chat-message--assistant is-assistant max-w-full",
|
|
550
304
|
className
|
|
551
305
|
);
|
|
552
|
-
return
|
|
306
|
+
return React.createElement(
|
|
553
307
|
ChatMessageRoleContext.Provider,
|
|
554
308
|
{ value: from },
|
|
555
|
-
|
|
309
|
+
React.createElement(Message, messageProps)
|
|
556
310
|
);
|
|
557
311
|
}
|
|
558
312
|
function ChatMessageContent({
|
|
@@ -560,9 +314,9 @@ function ChatMessageContent({
|
|
|
560
314
|
from,
|
|
561
315
|
...props
|
|
562
316
|
}) {
|
|
563
|
-
const inheritedRole =
|
|
317
|
+
const inheritedRole = React.useContext(ChatMessageRoleContext);
|
|
564
318
|
const isUser = (from ?? inheritedRole) === "user";
|
|
565
|
-
return
|
|
319
|
+
return React.createElement("div", {
|
|
566
320
|
className: cn(
|
|
567
321
|
"a24-chat-message-content flex max-w-full min-w-0 flex-col gap-2 text-sm",
|
|
568
322
|
isUser ? "a24-chat-message-content--user is-user:dark w-fit overflow-visible rounded-lg bg-secondary px-4 py-3 text-foreground" : "a24-chat-message-content--assistant w-full overflow-visible text-foreground",
|
|
@@ -576,7 +330,7 @@ function ChatMessageActions({
|
|
|
576
330
|
className,
|
|
577
331
|
...props
|
|
578
332
|
}) {
|
|
579
|
-
return
|
|
333
|
+
return React.createElement("div", {
|
|
580
334
|
className: cn("flex items-center gap-1", className),
|
|
581
335
|
"data-slot": "message-actions",
|
|
582
336
|
...props
|
|
@@ -591,7 +345,7 @@ function ChatMessageAction({
|
|
|
591
345
|
...props
|
|
592
346
|
}) {
|
|
593
347
|
const tooltipLabel = typeof tooltip === "string" ? tooltip : void 0;
|
|
594
|
-
return
|
|
348
|
+
return React.createElement(
|
|
595
349
|
"button",
|
|
596
350
|
{
|
|
597
351
|
"aria-label": label || tooltipLabel,
|
|
@@ -603,60 +357,310 @@ function ChatMessageAction({
|
|
|
603
357
|
type,
|
|
604
358
|
...props
|
|
605
359
|
},
|
|
606
|
-
children,
|
|
607
|
-
|
|
608
|
-
"span",
|
|
609
|
-
{ className: "sr-only" },
|
|
610
|
-
label || tooltipLabel
|
|
611
|
-
)
|
|
360
|
+
children,
|
|
361
|
+
React.createElement(
|
|
362
|
+
"span",
|
|
363
|
+
{ className: "sr-only" },
|
|
364
|
+
label || tooltipLabel
|
|
365
|
+
)
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
var resolvedContentCache = /* @__PURE__ */ new WeakMap();
|
|
369
|
+
var CONTENT_CACHE_EXPIRY_BUFFER_MS = 15e3;
|
|
370
|
+
var CONTENT_CACHE_MAX_ENTRIES = 100;
|
|
371
|
+
function attachmentCacheKey(data) {
|
|
372
|
+
const id = typeof data.id === "string" ? data.id.trim() : "";
|
|
373
|
+
return id || null;
|
|
374
|
+
}
|
|
375
|
+
function cachedAttachmentContent(resolver, data) {
|
|
376
|
+
const key = attachmentCacheKey(data);
|
|
377
|
+
if (!key) return null;
|
|
378
|
+
const cached = resolvedContentCache.get(resolver)?.get(key);
|
|
379
|
+
if (!cached) return null;
|
|
380
|
+
if (!cached.validUntil) return cached;
|
|
381
|
+
const validUntil = Date.parse(cached.validUntil);
|
|
382
|
+
if (Number.isFinite(validUntil) && validUntil - CONTENT_CACHE_EXPIRY_BUFFER_MS > Date.now()) {
|
|
383
|
+
return cached;
|
|
384
|
+
}
|
|
385
|
+
resolvedContentCache.get(resolver)?.delete(key);
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
function cacheAttachmentContent(resolver, data, result) {
|
|
389
|
+
const key = attachmentCacheKey(data);
|
|
390
|
+
if (!key) return;
|
|
391
|
+
const cache = resolvedContentCache.get(resolver) || /* @__PURE__ */ new Map();
|
|
392
|
+
cache.delete(key);
|
|
393
|
+
cache.set(key, result);
|
|
394
|
+
while (cache.size > CONTENT_CACHE_MAX_ENTRIES) {
|
|
395
|
+
const oldestKey = cache.keys().next().value;
|
|
396
|
+
if (typeof oldestKey !== "string") break;
|
|
397
|
+
cache.delete(oldestKey);
|
|
398
|
+
}
|
|
399
|
+
resolvedContentCache.set(resolver, cache);
|
|
400
|
+
}
|
|
401
|
+
function invalidateAttachmentContent(resolver, data) {
|
|
402
|
+
const key = attachmentCacheKey(data);
|
|
403
|
+
if (key) resolvedContentCache.get(resolver)?.delete(key);
|
|
404
|
+
}
|
|
405
|
+
function attachmentMediaType(data) {
|
|
406
|
+
return data.mediaType || data.contentType || String(data.type || "application/octet-stream");
|
|
407
|
+
}
|
|
408
|
+
function attachmentFilename(data) {
|
|
409
|
+
return data.filename || data.name || "Attachment";
|
|
410
|
+
}
|
|
411
|
+
function attachmentExtension(filename) {
|
|
412
|
+
const extension = filename.split(".").pop();
|
|
413
|
+
return extension && extension !== filename ? extension.toLowerCase() : "";
|
|
414
|
+
}
|
|
415
|
+
function resolveAttachmentVisual(data) {
|
|
416
|
+
const mediaType = attachmentMediaType(data).toLowerCase();
|
|
417
|
+
const extension = attachmentExtension(attachmentFilename(data));
|
|
418
|
+
if (mediaType.startsWith("image/") || ["avif", "gif", "heic", "jpeg", "jpg", "png", "svg", "webp"].includes(extension)) {
|
|
419
|
+
return { fileIconType: extension || "image", kind: "image" };
|
|
420
|
+
}
|
|
421
|
+
if (mediaType === "application/pdf" || extension === "pdf") {
|
|
422
|
+
return { fileIconType: "pdf", kind: "pdf" };
|
|
423
|
+
}
|
|
424
|
+
if (mediaType.includes("spreadsheet") || mediaType.includes("csv") || ["csv", "numbers", "ods", "xls", "xlsm", "xlsx"].includes(extension)) {
|
|
425
|
+
if (["csv", "xls", "xlsx"].includes(extension)) {
|
|
426
|
+
return { fileIconType: extension, kind: "spreadsheet" };
|
|
427
|
+
}
|
|
428
|
+
return { fileIconType: "spreadsheets", kind: "spreadsheet" };
|
|
429
|
+
}
|
|
430
|
+
if (mediaType.includes("presentation") || ["key", "odp", "ppt", "pptx"].includes(extension)) {
|
|
431
|
+
return { fileIconType: extension === "ppt" ? "ppt" : "pptx", kind: "presentation" };
|
|
432
|
+
}
|
|
433
|
+
if (mediaType.includes("word") || mediaType.includes("rtf") || ["doc", "docx", "odt", "rtf"].includes(extension)) {
|
|
434
|
+
if (extension === "doc" || extension === "docx") {
|
|
435
|
+
return { fileIconType: extension, kind: "document" };
|
|
436
|
+
}
|
|
437
|
+
return { fileIconType: "document", kind: "document" };
|
|
438
|
+
}
|
|
439
|
+
if (mediaType.startsWith("audio/") || ["aac", "flac", "m4a", "mp3", "ogg", "wav"].includes(extension)) {
|
|
440
|
+
if (extension === "mp3" || extension === "wav") {
|
|
441
|
+
return { fileIconType: extension, kind: "audio" };
|
|
442
|
+
}
|
|
443
|
+
return { fileIconType: "audio", kind: "audio" };
|
|
444
|
+
}
|
|
445
|
+
if (mediaType.startsWith("video/") || ["avi", "m4v", "mkv", "mov", "mp4", "webm"].includes(extension)) {
|
|
446
|
+
if (["avi", "mkv", "mp4", "mpeg"].includes(extension)) {
|
|
447
|
+
return { fileIconType: extension, kind: "video" };
|
|
448
|
+
}
|
|
449
|
+
return { fileIconType: "video", kind: "video" };
|
|
450
|
+
}
|
|
451
|
+
if (mediaType.includes("zip") || mediaType.includes("compressed") || ["7z", "bz2", "gz", "rar", "tar", "tgz", "zip"].includes(extension)) {
|
|
452
|
+
return { fileIconType: extension === "rar" ? "rar" : "zip", kind: "archive" };
|
|
453
|
+
}
|
|
454
|
+
if (mediaType.includes("json") || mediaType.includes("javascript") || mediaType.includes("typescript") || mediaType.includes("xml") || ["css", "html", "js", "jsx", "json", "py", "sql", "ts", "tsx", "xml", "yaml", "yml"].includes(extension)) {
|
|
455
|
+
if (["css", "html", "java", "js", "json", "sql", "xml"].includes(extension)) {
|
|
456
|
+
return { fileIconType: extension, kind: "code" };
|
|
457
|
+
}
|
|
458
|
+
return { fileIconType: "code", kind: "code" };
|
|
459
|
+
}
|
|
460
|
+
if (mediaType.startsWith("text/") || ["md", "markdown", "txt"].includes(extension)) {
|
|
461
|
+
return { fileIconType: "txt", kind: "file" };
|
|
462
|
+
}
|
|
463
|
+
return { fileIconType: "empty", kind: "file" };
|
|
464
|
+
}
|
|
465
|
+
function solidFileIconBackground(fileIconType, kind) {
|
|
466
|
+
if (["txt", "zip", "rar"].includes(fileIconType)) return "#344054";
|
|
467
|
+
if (kind === "pdf") return "#D92D20";
|
|
468
|
+
if (kind === "spreadsheet") return "#079455";
|
|
469
|
+
if (kind === "document" || kind === "video") return "#155EEF";
|
|
470
|
+
if (kind === "presentation") return "#E62E05";
|
|
471
|
+
if (kind === "audio") return "#DD2590";
|
|
472
|
+
if (kind === "code") return "#444CE7";
|
|
473
|
+
return "#7F56D9";
|
|
474
|
+
}
|
|
475
|
+
function isImageAttachment(data) {
|
|
476
|
+
return resolveAttachmentVisual(data).kind === "image";
|
|
477
|
+
}
|
|
478
|
+
function attachmentRenderKey(data, index, rowKind) {
|
|
479
|
+
const id = typeof data.id === "string" ? data.id.trim() : "";
|
|
480
|
+
const identity = id || `${attachmentFilename(data)}:${attachmentMediaType(data)}`;
|
|
481
|
+
return `${rowKind}:${identity}:${index}`;
|
|
482
|
+
}
|
|
483
|
+
function ChatImageAttachment({
|
|
484
|
+
className,
|
|
485
|
+
data,
|
|
486
|
+
onRemove,
|
|
487
|
+
resolveContent,
|
|
488
|
+
...props
|
|
489
|
+
}) {
|
|
490
|
+
const filename = attachmentFilename(data);
|
|
491
|
+
const initialUrl = typeof data.url === "string" ? data.url.trim() : "";
|
|
492
|
+
const contentStatus = String(data.contentStatus || data.content_status || "available");
|
|
493
|
+
const attachmentKey = attachmentCacheKey(data);
|
|
494
|
+
const dataRef = React.useRef(data);
|
|
495
|
+
dataRef.current = data;
|
|
496
|
+
const rootRef = React.useRef(null);
|
|
497
|
+
const retryCountRef = React.useRef(0);
|
|
498
|
+
const [isNearViewport, setIsNearViewport] = React.useState(Boolean(initialUrl));
|
|
499
|
+
const [sourceUrl, setSourceUrl] = React.useState(initialUrl);
|
|
500
|
+
const [status, setStatus] = React.useState(
|
|
501
|
+
initialUrl ? "loading" : contentStatus === "expired" || !resolveContent ? "error" : "idle"
|
|
502
|
+
);
|
|
503
|
+
const [resolutionAttempt, setResolutionAttempt] = React.useState(0);
|
|
504
|
+
React.useEffect(() => {
|
|
505
|
+
if (initialUrl && resolutionAttempt === 0 || contentStatus === "expired" || !resolveContent) return;
|
|
506
|
+
const node = rootRef.current;
|
|
507
|
+
if (!node || typeof IntersectionObserver === "undefined") {
|
|
508
|
+
setIsNearViewport(true);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const observer = new IntersectionObserver(
|
|
512
|
+
(entries) => {
|
|
513
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
514
|
+
setIsNearViewport(true);
|
|
515
|
+
observer.disconnect();
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
{ rootMargin: "240px" }
|
|
519
|
+
);
|
|
520
|
+
observer.observe(node);
|
|
521
|
+
return () => observer.disconnect();
|
|
522
|
+
}, [contentStatus, initialUrl, resolutionAttempt, resolveContent]);
|
|
523
|
+
React.useEffect(() => {
|
|
524
|
+
if (initialUrl && resolutionAttempt === 0) {
|
|
525
|
+
setSourceUrl(initialUrl);
|
|
526
|
+
setStatus("loading");
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
if (!isNearViewport || !resolveContent || contentStatus === "expired") return;
|
|
530
|
+
const attachment = dataRef.current;
|
|
531
|
+
const cached = cachedAttachmentContent(resolveContent, attachment);
|
|
532
|
+
if (cached) {
|
|
533
|
+
setSourceUrl(cached.url);
|
|
534
|
+
setStatus("loading");
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const controller = new AbortController();
|
|
538
|
+
setStatus("resolving");
|
|
539
|
+
void resolveContent(attachment, controller.signal).then((result) => {
|
|
540
|
+
if (controller.signal.aborted) return;
|
|
541
|
+
if (!result.url?.trim()) throw new Error("Attachment content resolver returned an empty URL");
|
|
542
|
+
cacheAttachmentContent(resolveContent, attachment, result);
|
|
543
|
+
setSourceUrl(result.url);
|
|
544
|
+
setStatus("loading");
|
|
545
|
+
}).catch(() => {
|
|
546
|
+
if (!controller.signal.aborted) setStatus("error");
|
|
547
|
+
});
|
|
548
|
+
return () => controller.abort();
|
|
549
|
+
}, [attachmentKey, contentStatus, initialUrl, isNearViewport, resolutionAttempt, resolveContent]);
|
|
550
|
+
const handleImageError = () => {
|
|
551
|
+
if (resolveContent && retryCountRef.current === 0) {
|
|
552
|
+
retryCountRef.current = 1;
|
|
553
|
+
invalidateAttachmentContent(resolveContent, dataRef.current);
|
|
554
|
+
setSourceUrl("");
|
|
555
|
+
setStatus("resolving");
|
|
556
|
+
setResolutionAttempt((current) => current + 1);
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
setStatus("error");
|
|
560
|
+
};
|
|
561
|
+
return React.createElement(
|
|
562
|
+
Attachment,
|
|
563
|
+
{
|
|
564
|
+
...props,
|
|
565
|
+
className: cn("a24-chat-image-attachment", className),
|
|
566
|
+
orientation: "vertical",
|
|
567
|
+
ref: rootRef,
|
|
568
|
+
state: status === "error" ? "error" : status === "done" ? "done" : "processing",
|
|
569
|
+
title: filename
|
|
570
|
+
},
|
|
571
|
+
React.createElement(
|
|
572
|
+
AttachmentMedia,
|
|
573
|
+
{ className: "a24-chat-image-media", variant: "image" },
|
|
574
|
+
sourceUrl ? React.createElement("img", {
|
|
575
|
+
alt: filename,
|
|
576
|
+
decoding: "async",
|
|
577
|
+
loading: "lazy",
|
|
578
|
+
onError: handleImageError,
|
|
579
|
+
onLoad: () => setStatus("done"),
|
|
580
|
+
src: sourceUrl
|
|
581
|
+
}) : status === "error" ? React.createElement(ImageOff, { "aria-hidden": "true", className: "size-5" }) : React.createElement(LoaderCircle, {
|
|
582
|
+
"aria-hidden": "true",
|
|
583
|
+
className: "a24-chat-image-spinner size-5 animate-spin"
|
|
584
|
+
}),
|
|
585
|
+
status !== "done" && status !== "error" ? React.createElement("span", { className: "sr-only", role: "status" }, `Loading ${filename}`) : null,
|
|
586
|
+
status === "error" ? React.createElement("span", { className: "sr-only" }, `${filename} preview unavailable`) : null
|
|
587
|
+
),
|
|
588
|
+
onRemove ? React.createElement(
|
|
589
|
+
"button",
|
|
590
|
+
{
|
|
591
|
+
"aria-label": `Remove ${filename}`,
|
|
592
|
+
className: "a24-chat-image-remove",
|
|
593
|
+
onClick: (event) => {
|
|
594
|
+
event.stopPropagation();
|
|
595
|
+
onRemove();
|
|
596
|
+
},
|
|
597
|
+
type: "button"
|
|
598
|
+
},
|
|
599
|
+
React.createElement(X, { "aria-hidden": "true", className: "size-3.5" })
|
|
600
|
+
) : null
|
|
612
601
|
);
|
|
613
602
|
}
|
|
614
603
|
function ChatAttachment({
|
|
604
|
+
className,
|
|
615
605
|
data,
|
|
616
606
|
onRemove,
|
|
617
607
|
orientation,
|
|
608
|
+
resolveContent,
|
|
618
609
|
...props
|
|
619
610
|
}) {
|
|
620
|
-
const
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
611
|
+
const filename = attachmentFilename(data);
|
|
612
|
+
const { fileIconType, kind } = resolveAttachmentVisual(data);
|
|
613
|
+
if (kind === "image") {
|
|
614
|
+
return React.createElement(ChatImageAttachment, {
|
|
615
|
+
...props,
|
|
616
|
+
className,
|
|
617
|
+
data,
|
|
618
|
+
onRemove,
|
|
619
|
+
resolveContent
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
return React.createElement(
|
|
624
623
|
Attachment,
|
|
625
624
|
{
|
|
626
|
-
|
|
625
|
+
className: cn("a24-chat-attachment", className),
|
|
626
|
+
orientation: orientation || "horizontal",
|
|
627
|
+
size: "sm",
|
|
627
628
|
...props
|
|
628
629
|
},
|
|
629
|
-
|
|
630
|
+
React.createElement(
|
|
630
631
|
AttachmentMedia,
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
"
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
632
|
+
Object.assign(
|
|
633
|
+
{
|
|
634
|
+
className: "a24-chat-attachment-icon",
|
|
635
|
+
style: { backgroundColor: solidFileIconBackground(fileIconType, kind) },
|
|
636
|
+
variant: "icon"
|
|
637
|
+
},
|
|
638
|
+
{ "data-file-kind": kind }
|
|
639
|
+
),
|
|
640
|
+
React.createElement(FileIcon, {
|
|
641
|
+
"aria-hidden": "true",
|
|
642
|
+
size: 28,
|
|
643
|
+
type: fileIconType,
|
|
644
|
+
variant: "solid"
|
|
645
|
+
})
|
|
641
646
|
),
|
|
642
|
-
|
|
647
|
+
React.createElement(
|
|
643
648
|
AttachmentContent,
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
React2.createElement(AttachmentDescription, null, mediaType)
|
|
649
|
+
{ className: "a24-chat-attachment-content" },
|
|
650
|
+
React.createElement(AttachmentTitle, { title: filename }, filename)
|
|
647
651
|
),
|
|
648
|
-
onRemove ?
|
|
652
|
+
onRemove ? React.createElement(
|
|
649
653
|
"button",
|
|
650
654
|
{
|
|
651
655
|
"aria-label": "Remove attachment",
|
|
652
|
-
className: "relative z-20
|
|
656
|
+
className: "relative z-20 inline-flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
653
657
|
onClick: (event) => {
|
|
654
658
|
event.stopPropagation();
|
|
655
659
|
onRemove();
|
|
656
660
|
},
|
|
657
661
|
type: "button"
|
|
658
662
|
},
|
|
659
|
-
|
|
663
|
+
React.createElement(X, { "aria-hidden": "true", className: "size-3.5" })
|
|
660
664
|
) : null
|
|
661
665
|
);
|
|
662
666
|
}
|
|
@@ -666,12 +670,11 @@ function ChatAttachments({
|
|
|
666
670
|
...props
|
|
667
671
|
}) {
|
|
668
672
|
if (!children) return null;
|
|
669
|
-
return
|
|
673
|
+
return React.createElement(
|
|
670
674
|
AttachmentGroup,
|
|
671
675
|
{
|
|
672
676
|
className: cn(
|
|
673
|
-
|
|
674
|
-
"w-fit flex-wrap overflow-visible",
|
|
677
|
+
"a24-chat-attachments w-full flex-nowrap",
|
|
675
678
|
className
|
|
676
679
|
),
|
|
677
680
|
...props
|
|
@@ -679,8 +682,305 @@ function ChatAttachments({
|
|
|
679
682
|
children
|
|
680
683
|
);
|
|
681
684
|
}
|
|
685
|
+
function ChatAttachmentRows({
|
|
686
|
+
attachments,
|
|
687
|
+
className,
|
|
688
|
+
dir,
|
|
689
|
+
onRemove,
|
|
690
|
+
resolveContent,
|
|
691
|
+
...props
|
|
692
|
+
}) {
|
|
693
|
+
if (attachments.length === 0) return null;
|
|
694
|
+
const imageAttachments = attachments.filter(isImageAttachment);
|
|
695
|
+
const fileAttachments = attachments.filter((attachment) => !isImageAttachment(attachment));
|
|
696
|
+
const renderRow = (items, kind) => items.length > 0 ? React.createElement(
|
|
697
|
+
ChatAttachments,
|
|
698
|
+
Object.assign({ dir, key: kind }, { "data-attachment-row": kind }),
|
|
699
|
+
items.map(
|
|
700
|
+
(attachment, index) => React.createElement(ChatAttachment, {
|
|
701
|
+
data: attachment,
|
|
702
|
+
dir: "ltr",
|
|
703
|
+
key: attachmentRenderKey(attachment, index, kind),
|
|
704
|
+
onRemove: onRemove ? () => onRemove(attachment) : void 0,
|
|
705
|
+
resolveContent
|
|
706
|
+
})
|
|
707
|
+
)
|
|
708
|
+
) : null;
|
|
709
|
+
return React.createElement(
|
|
710
|
+
"div",
|
|
711
|
+
{
|
|
712
|
+
className: cn("a24-chat-attachment-rows", className),
|
|
713
|
+
dir,
|
|
714
|
+
...props
|
|
715
|
+
},
|
|
716
|
+
renderRow(imageAttachments, "images"),
|
|
717
|
+
renderRow(fileAttachments, "files")
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/ui/composer-attachments.ts
|
|
722
|
+
var createId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
723
|
+
function createAgentChatComposerFile(file) {
|
|
724
|
+
return {
|
|
725
|
+
id: createId(),
|
|
726
|
+
type: "file",
|
|
727
|
+
url: URL.createObjectURL(file),
|
|
728
|
+
filename: file.name || "attachment",
|
|
729
|
+
mediaType: file.type || "application/octet-stream",
|
|
730
|
+
source: file
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function revokeAgentChatComposerFiles(files) {
|
|
734
|
+
files.forEach((file) => {
|
|
735
|
+
try {
|
|
736
|
+
URL.revokeObjectURL(file.url);
|
|
737
|
+
} catch {
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// src/ui/agent-chat-composer.tsx
|
|
743
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
744
|
+
function formatFileCount(files) {
|
|
745
|
+
if (files.length === 1) return files[0].filename;
|
|
746
|
+
return `${files.length} files`;
|
|
747
|
+
}
|
|
748
|
+
var pillButtonClass = "inline-flex size-8 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-muted text-sm text-muted-foreground shadow-none transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
749
|
+
var submitButtonClass = "inline-flex size-9 shrink-0 items-center justify-center gap-2 rounded-lg border-0 bg-primary text-sm text-primary-foreground shadow-none transition-[background-color,color,opacity,transform] duration-200 hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50";
|
|
750
|
+
function AgentChatComposer({
|
|
751
|
+
accept,
|
|
752
|
+
allowAttachments = true,
|
|
753
|
+
attachmentLayout = "flow",
|
|
754
|
+
className,
|
|
755
|
+
disabled = false,
|
|
756
|
+
forceExpanded = false,
|
|
757
|
+
inputToolbarContent,
|
|
758
|
+
isRunning = false,
|
|
759
|
+
onAttachmentCountChange,
|
|
760
|
+
onStop,
|
|
761
|
+
onSubmit,
|
|
762
|
+
placeholder = "Message the agent",
|
|
763
|
+
textareaRef
|
|
764
|
+
}) {
|
|
765
|
+
const fileInputRef = React2.useRef(null);
|
|
766
|
+
const filesRef = React2.useRef([]);
|
|
767
|
+
const inFlightFilesRef = React2.useRef([]);
|
|
768
|
+
const localTextareaRef = React2.useRef(null);
|
|
769
|
+
const draftRevisionRef = React2.useRef(0);
|
|
770
|
+
const [text, setText] = React2.useState("");
|
|
771
|
+
const [files, setFiles] = React2.useState([]);
|
|
772
|
+
const [isSubmitting, setIsSubmitting] = React2.useState(false);
|
|
773
|
+
const isExpanded = forceExpanded || text.includes("\n") || text.length > 62;
|
|
774
|
+
const setTextareaRef = React2.useCallback(
|
|
775
|
+
(node) => {
|
|
776
|
+
localTextareaRef.current = node;
|
|
777
|
+
if (typeof textareaRef === "function") {
|
|
778
|
+
textareaRef(node);
|
|
779
|
+
} else if (textareaRef) {
|
|
780
|
+
textareaRef.current = node;
|
|
781
|
+
}
|
|
782
|
+
},
|
|
783
|
+
[textareaRef]
|
|
784
|
+
);
|
|
785
|
+
React2.useEffect(() => {
|
|
786
|
+
filesRef.current = files;
|
|
787
|
+
onAttachmentCountChange?.(files.length);
|
|
788
|
+
}, [files, onAttachmentCountChange]);
|
|
789
|
+
React2.useEffect(() => () => {
|
|
790
|
+
revokeAgentChatComposerFiles(filesRef.current);
|
|
791
|
+
revokeAgentChatComposerFiles(inFlightFilesRef.current);
|
|
792
|
+
}, []);
|
|
793
|
+
React2.useLayoutEffect(() => {
|
|
794
|
+
const textarea = localTextareaRef.current;
|
|
795
|
+
if (!textarea) return;
|
|
796
|
+
if (isExpanded) {
|
|
797
|
+
textarea.style.height = "auto";
|
|
798
|
+
const scrollHeight = textarea.scrollHeight;
|
|
799
|
+
textarea.style.height = `${Math.min(scrollHeight, 224)}px`;
|
|
800
|
+
textarea.style.overflowY = scrollHeight >= 224 ? "auto" : "hidden";
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
textarea.style.height = "";
|
|
804
|
+
textarea.style.overflowY = "hidden";
|
|
805
|
+
}, [isExpanded, text]);
|
|
806
|
+
const canSubmit = !disabled && !isSubmitting && !isRunning && (text.trim().length > 0 || files.length > 0);
|
|
807
|
+
const handleFilesChange = (event) => {
|
|
808
|
+
const selected = Array.from(event.target.files || []).map(createAgentChatComposerFile);
|
|
809
|
+
if (selected.length > 0) {
|
|
810
|
+
draftRevisionRef.current += 1;
|
|
811
|
+
setFiles((current) => [...current, ...selected]);
|
|
812
|
+
}
|
|
813
|
+
event.currentTarget.value = "";
|
|
814
|
+
};
|
|
815
|
+
const removeFile = (fileId) => {
|
|
816
|
+
draftRevisionRef.current += 1;
|
|
817
|
+
setFiles((current) => {
|
|
818
|
+
const target = current.find((file) => file.id === fileId);
|
|
819
|
+
if (target) revokeAgentChatComposerFiles([target]);
|
|
820
|
+
return current.filter((file) => file.id !== fileId);
|
|
821
|
+
});
|
|
822
|
+
};
|
|
823
|
+
const submit = async () => {
|
|
824
|
+
if (!canSubmit) return;
|
|
825
|
+
const submittedText = text.trim();
|
|
826
|
+
const submittedFiles = files;
|
|
827
|
+
const clearedRevision = draftRevisionRef.current + 1;
|
|
828
|
+
draftRevisionRef.current = clearedRevision;
|
|
829
|
+
inFlightFilesRef.current = submittedFiles;
|
|
830
|
+
setIsSubmitting(true);
|
|
831
|
+
setText("");
|
|
832
|
+
setFiles([]);
|
|
833
|
+
try {
|
|
834
|
+
await onSubmit({ text: submittedText, files: submittedFiles });
|
|
835
|
+
revokeAgentChatComposerFiles(submittedFiles);
|
|
836
|
+
inFlightFilesRef.current = [];
|
|
837
|
+
} catch {
|
|
838
|
+
if (draftRevisionRef.current === clearedRevision) {
|
|
839
|
+
draftRevisionRef.current += 1;
|
|
840
|
+
setText(submittedText);
|
|
841
|
+
setFiles(submittedFiles);
|
|
842
|
+
inFlightFilesRef.current = [];
|
|
843
|
+
} else {
|
|
844
|
+
revokeAgentChatComposerFiles(submittedFiles);
|
|
845
|
+
inFlightFilesRef.current = [];
|
|
846
|
+
}
|
|
847
|
+
} finally {
|
|
848
|
+
setIsSubmitting(false);
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
const handleKeyDown = (event) => {
|
|
852
|
+
if (event.key === "Enter" && !event.shiftKey) {
|
|
853
|
+
event.preventDefault();
|
|
854
|
+
void submit();
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("a24-composer relative mx-auto w-full max-w-3xl overflow-visible", className), "data-agents24-chat-composer": "", children: [
|
|
858
|
+
files.length > 0 ? /* @__PURE__ */ jsx3(
|
|
859
|
+
"div",
|
|
860
|
+
{
|
|
861
|
+
"data-testid": "agent-chat-composer-attachments",
|
|
862
|
+
"data-layout": attachmentLayout,
|
|
863
|
+
className: cn(
|
|
864
|
+
"a24-composer__attachments min-w-0 py-1",
|
|
865
|
+
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"
|
|
866
|
+
),
|
|
867
|
+
children: /* @__PURE__ */ jsx3(
|
|
868
|
+
ChatAttachmentRows,
|
|
869
|
+
{
|
|
870
|
+
attachments: files,
|
|
871
|
+
onRemove: (attachment) => attachment.id && removeFile(attachment.id)
|
|
872
|
+
}
|
|
873
|
+
)
|
|
874
|
+
}
|
|
875
|
+
) : null,
|
|
876
|
+
/* @__PURE__ */ jsx3(
|
|
877
|
+
"div",
|
|
878
|
+
{
|
|
879
|
+
"data-expanded": isExpanded ? "" : void 0,
|
|
880
|
+
className: cn(
|
|
881
|
+
"a24-composer__surface relative w-full border border-input bg-background shadow-sm",
|
|
882
|
+
isExpanded ? "rounded-xl p-2 pb-1.5" : "rounded-xl px-2 py-[3px]"
|
|
883
|
+
),
|
|
884
|
+
children: /* @__PURE__ */ jsxs(
|
|
885
|
+
"div",
|
|
886
|
+
{
|
|
887
|
+
className: "a24-composer__grid w-full",
|
|
888
|
+
style: {
|
|
889
|
+
alignItems: "center",
|
|
890
|
+
display: "grid",
|
|
891
|
+
gridTemplateAreas: isExpanded ? `"textarea textarea textarea" "plus toolbar submit"` : `"plus textarea composer mic submit"`,
|
|
892
|
+
gridTemplateColumns: isExpanded ? "auto 1fr auto" : "auto 1fr auto auto auto",
|
|
893
|
+
gap: isExpanded ? "3px 10px" : "8px"
|
|
894
|
+
},
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ jsxs("div", { style: { gridArea: "plus" }, className: "a24-composer__attach-slot flex shrink-0 items-center justify-center", children: [
|
|
897
|
+
/* @__PURE__ */ jsx3(
|
|
898
|
+
"input",
|
|
899
|
+
{
|
|
900
|
+
ref: fileInputRef,
|
|
901
|
+
accept,
|
|
902
|
+
"aria-label": "Attach files",
|
|
903
|
+
className: "hidden",
|
|
904
|
+
multiple: true,
|
|
905
|
+
name: "attachments",
|
|
906
|
+
onChange: handleFilesChange,
|
|
907
|
+
type: "file"
|
|
908
|
+
}
|
|
909
|
+
),
|
|
910
|
+
/* @__PURE__ */ jsx3(
|
|
911
|
+
"button",
|
|
912
|
+
{
|
|
913
|
+
"aria-label": "Attach files",
|
|
914
|
+
className: cn("a24-composer__attach", pillButtonClass),
|
|
915
|
+
disabled: disabled || isSubmitting || isRunning || !allowAttachments,
|
|
916
|
+
onClick: () => fileInputRef.current?.click(),
|
|
917
|
+
title: "Attach files",
|
|
918
|
+
type: "button",
|
|
919
|
+
children: /* @__PURE__ */ jsx3(Plus, { className: "size-4" })
|
|
920
|
+
}
|
|
921
|
+
)
|
|
922
|
+
] }),
|
|
923
|
+
/* @__PURE__ */ jsx3("div", { style: { gridArea: "textarea" }, className: "a24-composer__textarea-slot min-w-0 w-full", children: /* @__PURE__ */ jsx3(
|
|
924
|
+
"textarea",
|
|
925
|
+
{
|
|
926
|
+
ref: setTextareaRef,
|
|
927
|
+
"aria-label": "Message",
|
|
928
|
+
autoComplete: "off",
|
|
929
|
+
className: cn(
|
|
930
|
+
"a24-composer__textarea w-full resize-none border-0 bg-transparent px-1 text-[15px] leading-relaxed text-foreground shadow-none outline-none placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0",
|
|
931
|
+
isExpanded ? "min-h-9 max-h-[224px] py-1" : "min-h-9 h-9 max-h-9 py-2"
|
|
932
|
+
),
|
|
933
|
+
disabled: disabled || isSubmitting || isRunning,
|
|
934
|
+
name: "message",
|
|
935
|
+
onChange: (event) => {
|
|
936
|
+
draftRevisionRef.current += 1;
|
|
937
|
+
setText(event.target.value);
|
|
938
|
+
},
|
|
939
|
+
onKeyDown: handleKeyDown,
|
|
940
|
+
placeholder,
|
|
941
|
+
rows: isExpanded ? 2 : 1,
|
|
942
|
+
value: text
|
|
943
|
+
}
|
|
944
|
+
) }),
|
|
945
|
+
isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "toolbar" }, className: "a24-composer__toolbar flex min-w-0 items-center gap-1.5", children: inputToolbarContent }) : null,
|
|
946
|
+
!isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "composer" }, className: "flex min-w-0 items-center gap-1.5" }) : null,
|
|
947
|
+
!isExpanded ? /* @__PURE__ */ jsx3("div", { style: { gridArea: "mic" }, className: "flex shrink-0 items-center justify-end" }) : null,
|
|
948
|
+
/* @__PURE__ */ jsx3("div", { style: { gridArea: "submit" }, className: "a24-composer__submit-slot flex shrink-0 items-center justify-end", children: isRunning ? /* @__PURE__ */ jsx3(
|
|
949
|
+
"button",
|
|
950
|
+
{
|
|
951
|
+
"aria-label": "Stop generating",
|
|
952
|
+
className: cn("a24-composer__submit", submitButtonClass),
|
|
953
|
+
disabled: disabled || !onStop,
|
|
954
|
+
onClick: onStop,
|
|
955
|
+
title: "Stop",
|
|
956
|
+
type: "button",
|
|
957
|
+
children: /* @__PURE__ */ jsx3(Square, { className: "size-3.5 fill-current" })
|
|
958
|
+
}
|
|
959
|
+
) : /* @__PURE__ */ jsx3(
|
|
960
|
+
"button",
|
|
961
|
+
{
|
|
962
|
+
"aria-label": files.length > 0 ? `Send ${formatFileCount(files)}` : "Send message",
|
|
963
|
+
className: cn("a24-composer__submit", submitButtonClass, text.trim().length > 0 && "hover:scale-105"),
|
|
964
|
+
disabled: !canSubmit,
|
|
965
|
+
onClick: () => void submit(),
|
|
966
|
+
title: "Send",
|
|
967
|
+
type: "button",
|
|
968
|
+
children: /* @__PURE__ */ jsx3(ArrowUp, { className: "size-4", strokeWidth: 2.5 })
|
|
969
|
+
}
|
|
970
|
+
) })
|
|
971
|
+
]
|
|
972
|
+
}
|
|
973
|
+
)
|
|
974
|
+
}
|
|
975
|
+
),
|
|
976
|
+
!isExpanded && inputToolbarContent ? /* @__PURE__ */ jsx3("div", { className: "a24-composer__toolbar a24-composer__toolbar--external mt-2 flex items-center gap-2 px-1", children: inputToolbarContent }) : null
|
|
977
|
+
] });
|
|
978
|
+
}
|
|
682
979
|
|
|
683
980
|
// src/ui/agent-chat-actions.tsx
|
|
981
|
+
import * as React3 from "react";
|
|
982
|
+
import { Check, Copy, RefreshCcw, ThumbsDown, ThumbsUp } from "lucide-react";
|
|
983
|
+
import { Popover } from "radix-ui";
|
|
684
984
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
685
985
|
var FEEDBACK_REASONS = [
|
|
686
986
|
["incorrect", "Incorrect"],
|
|
@@ -1559,6 +1859,7 @@ function toolRowLabel(part) {
|
|
|
1559
1859
|
function ToolDisclosure({
|
|
1560
1860
|
children,
|
|
1561
1861
|
error,
|
|
1862
|
+
grouped,
|
|
1562
1863
|
label,
|
|
1563
1864
|
loading,
|
|
1564
1865
|
onExpandedChange,
|
|
@@ -1572,9 +1873,10 @@ function ToolDisclosure({
|
|
|
1572
1873
|
const [open, setOpen] = React6.useState(false);
|
|
1573
1874
|
const contentId = React6.useId();
|
|
1574
1875
|
const expandable = React6.Children.toArray(children).length > 0;
|
|
1876
|
+
const textOnlyRoot = Boolean(root && !grouped && !showOrb);
|
|
1575
1877
|
if (!expandable) {
|
|
1576
1878
|
const triggerClassName = cn("a24-tool-trigger", root && "a24-tool-trigger--root", root && !showOrb && "a24-tool-trigger--without-orb", error && "a24-tool-trigger--error", loading && "a24-tool-trigger--active");
|
|
1577
|
-
return /* @__PURE__ */ jsxs4("div", { className: "a24-tool-trigger-row", children: [
|
|
1879
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("a24-tool-trigger-row", textOnlyRoot && "a24-tool-trigger-row--text"), children: [
|
|
1578
1880
|
onSelect && part ? /* @__PURE__ */ jsxs4("button", { className: triggerClassName, onClick: () => onSelect(part), type: "button", children: [
|
|
1579
1881
|
showOrb ? /* @__PURE__ */ jsx8(ToolActivityOrb, { label: statusLabel }) : null,
|
|
1580
1882
|
/* @__PURE__ */ jsx8("span", { className: "a24-tool-trigger__label", children: label })
|
|
@@ -1586,7 +1888,7 @@ function ToolDisclosure({
|
|
|
1586
1888
|
] });
|
|
1587
1889
|
}
|
|
1588
1890
|
return /* @__PURE__ */ jsxs4("div", { className: "a24-tool-disclosure", children: [
|
|
1589
|
-
/* @__PURE__ */ jsxs4("div", { className: "a24-tool-trigger-row", children: [
|
|
1891
|
+
/* @__PURE__ */ jsxs4("div", { className: cn("a24-tool-trigger-row", textOnlyRoot && "a24-tool-trigger-row--text"), children: [
|
|
1590
1892
|
/* @__PURE__ */ jsxs4(
|
|
1591
1893
|
"button",
|
|
1592
1894
|
{
|
|
@@ -1711,6 +2013,7 @@ function AgentChatToolSession({
|
|
|
1711
2013
|
{
|
|
1712
2014
|
accessory: slots?.renderToolAccessory?.(context),
|
|
1713
2015
|
error: failed,
|
|
2016
|
+
grouped: true,
|
|
1714
2017
|
label: labelContent,
|
|
1715
2018
|
loading: presentingActivity,
|
|
1716
2019
|
onExpandedChange: slots?.onExpandedChange,
|
|
@@ -1755,6 +2058,7 @@ function AgentChatSubagentGroup({ isLatestActivity = true, isLive = false, part,
|
|
|
1755
2058
|
{
|
|
1756
2059
|
accessory: slots?.renderToolAccessory?.(context),
|
|
1757
2060
|
error: failed,
|
|
2061
|
+
grouped: true,
|
|
1758
2062
|
label: labelContent,
|
|
1759
2063
|
loading: presentingActivity,
|
|
1760
2064
|
onExpandedChange: slots?.onExpandedChange,
|
|
@@ -2095,6 +2399,7 @@ function AgentChatMessage({
|
|
|
2095
2399
|
additionalActions,
|
|
2096
2400
|
actions,
|
|
2097
2401
|
actionsClassName,
|
|
2402
|
+
attachmentContentResolver,
|
|
2098
2403
|
className,
|
|
2099
2404
|
contentClassName,
|
|
2100
2405
|
dir,
|
|
@@ -2128,14 +2433,15 @@ function AgentChatMessage({
|
|
|
2128
2433
|
}
|
|
2129
2434
|
) : null);
|
|
2130
2435
|
return /* @__PURE__ */ jsxs6(ChatMessage, { className, dir, from: message.role, children: [
|
|
2131
|
-
showAttachments ? /* @__PURE__ */ jsx10(
|
|
2132
|
-
|
|
2436
|
+
showAttachments ? /* @__PURE__ */ jsx10(
|
|
2437
|
+
ChatAttachmentRows,
|
|
2133
2438
|
{
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2439
|
+
attachments: message.attachments || [],
|
|
2440
|
+
className: "mb-2",
|
|
2441
|
+
dir,
|
|
2442
|
+
resolveContent: attachmentContentResolver
|
|
2443
|
+
}
|
|
2444
|
+
) : null,
|
|
2139
2445
|
shouldRenderContent ? /* @__PURE__ */ jsxs6(
|
|
2140
2446
|
ChatMessageContent,
|
|
2141
2447
|
{
|
|
@@ -2590,6 +2896,7 @@ export {
|
|
|
2590
2896
|
BubbleGroup,
|
|
2591
2897
|
BubbleReactions,
|
|
2592
2898
|
ChatAttachment,
|
|
2899
|
+
ChatAttachmentRows,
|
|
2593
2900
|
ChatAttachments,
|
|
2594
2901
|
ChatMessage,
|
|
2595
2902
|
ChatMessageAction,
|
|
@@ -2603,6 +2910,7 @@ export {
|
|
|
2603
2910
|
ChatMessageAction as MessageAction,
|
|
2604
2911
|
ChatMessageActions as MessageActions,
|
|
2605
2912
|
ChatAttachment as MessageAttachment,
|
|
2913
|
+
ChatAttachmentRows as MessageAttachmentRows,
|
|
2606
2914
|
ChatAttachments as MessageAttachments,
|
|
2607
2915
|
MessageAvatar,
|
|
2608
2916
|
ChatMessageContent as MessageContent,
|
|
@@ -2618,6 +2926,7 @@ export {
|
|
|
2618
2926
|
bubbleVariants,
|
|
2619
2927
|
cn,
|
|
2620
2928
|
contextStatusMetrics,
|
|
2929
|
+
createAgentChatComposerFile,
|
|
2621
2930
|
hitlActionLabel,
|
|
2622
2931
|
hitlTitle,
|
|
2623
2932
|
isAgentChatSubagent,
|
|
@@ -2626,6 +2935,7 @@ export {
|
|
|
2626
2935
|
markerVariants,
|
|
2627
2936
|
partitionAgentChatToolTimeline,
|
|
2628
2937
|
resolvedHitlLabel,
|
|
2938
|
+
revokeAgentChatComposerFiles,
|
|
2629
2939
|
shouldCollapseUserMessage,
|
|
2630
2940
|
useAudioRecorder
|
|
2631
2941
|
};
|