@invergent/agent-chat-react 1.6.9 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +667 -204
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -3
- package/dist/index.d.ts +62 -3
- package/dist/index.js +665 -205
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cn } from './chunk-QSC4UIVT.js';
|
|
2
2
|
import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, lazy, useContext, Suspense, Children } from 'react';
|
|
3
|
-
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, EyeIcon, GlobeIcon, CheckIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, InboxIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
3
|
+
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, EyeIcon, GlobeIcon, CheckIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, InboxIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
import { Collapsible as Collapsible$1, Slot, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Tooltip as Tooltip$1, Tabs as Tabs$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, HoverCard as HoverCard$1, Progress as Progress$1 } from 'radix-ui';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -4193,11 +4193,72 @@ var ChatMessage = memo(function ChatMessage2({
|
|
|
4193
4193
|
className: "max-w-64 max-h-48 rounded-lg border border-border object-contain"
|
|
4194
4194
|
},
|
|
4195
4195
|
i
|
|
4196
|
+
)) }),
|
|
4197
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mt-2", children: message.attachments.map((a, i) => /* @__PURE__ */ jsx(
|
|
4198
|
+
AttachmentChip,
|
|
4199
|
+
{
|
|
4200
|
+
attachment: a,
|
|
4201
|
+
onSelect: onFileSelect
|
|
4202
|
+
},
|
|
4203
|
+
a.path ?? `pending-${i}`
|
|
4196
4204
|
)) })
|
|
4197
4205
|
] }) });
|
|
4198
4206
|
}
|
|
4199
4207
|
return /* @__PURE__ */ jsx(AssistantMessage, { message, isLast, onFileSelect });
|
|
4200
4208
|
});
|
|
4209
|
+
function iconForMime(mime) {
|
|
4210
|
+
if (!mime) return File$1;
|
|
4211
|
+
if (mime.startsWith("image/")) return FileImage;
|
|
4212
|
+
if (mime.startsWith("audio/")) return FileAudio;
|
|
4213
|
+
if (mime.startsWith("video/")) return FileVideo;
|
|
4214
|
+
if (mime === "application/pdf") return FileText;
|
|
4215
|
+
if (mime.startsWith("text/")) return FileText;
|
|
4216
|
+
if (mime === "application/json" || mime === "application/xml" || mime.endsWith("+xml") || mime.endsWith("+json") || mime.includes("javascript") || mime.includes("typescript")) {
|
|
4217
|
+
return FileCode;
|
|
4218
|
+
}
|
|
4219
|
+
if (mime === "application/zip" || mime === "application/x-7z-compressed" || mime === "application/x-tar" || mime === "application/gzip" || mime === "application/x-rar-compressed") {
|
|
4220
|
+
return FileArchive;
|
|
4221
|
+
}
|
|
4222
|
+
if (mime === "text/csv" || mime === "application/vnd.ms-excel" || mime.includes("spreadsheet")) {
|
|
4223
|
+
return FileSpreadsheet;
|
|
4224
|
+
}
|
|
4225
|
+
return File$1;
|
|
4226
|
+
}
|
|
4227
|
+
function formatBytes(n) {
|
|
4228
|
+
if (n == null || !Number.isFinite(n) || n < 0) return "";
|
|
4229
|
+
for (const [unit, divisor] of [
|
|
4230
|
+
["GB", 1e9],
|
|
4231
|
+
["MB", 1e6],
|
|
4232
|
+
["KB", 1e3]
|
|
4233
|
+
]) {
|
|
4234
|
+
if (n >= divisor) return `${(n / divisor).toFixed(1)} ${unit}`;
|
|
4235
|
+
}
|
|
4236
|
+
return `${n} B`;
|
|
4237
|
+
}
|
|
4238
|
+
function AttachmentChip({
|
|
4239
|
+
attachment,
|
|
4240
|
+
onSelect
|
|
4241
|
+
}) {
|
|
4242
|
+
const Icon = iconForMime(attachment.mimeType);
|
|
4243
|
+
const clickable = !!attachment.path && !!onSelect;
|
|
4244
|
+
const sizeLabel = formatBytes(attachment.size);
|
|
4245
|
+
return /* @__PURE__ */ jsxs(
|
|
4246
|
+
"button",
|
|
4247
|
+
{
|
|
4248
|
+
type: "button",
|
|
4249
|
+
onClick: clickable ? () => onSelect(attachment.path) : void 0,
|
|
4250
|
+
disabled: !clickable,
|
|
4251
|
+
title: attachment.filename,
|
|
4252
|
+
"aria-label": clickable ? `Open ${attachment.filename}` : `${attachment.filename} (uploading)`,
|
|
4253
|
+
className: "inline-flex items-center gap-2 rounded-md border border-border bg-muted/40 px-2 py-1 text-xs max-w-[16rem] " + (clickable ? "hover:bg-muted cursor-pointer" : "opacity-60 cursor-default"),
|
|
4254
|
+
children: [
|
|
4255
|
+
/* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0" }),
|
|
4256
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: attachment.filename }),
|
|
4257
|
+
sizeLabel && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground shrink-0", children: sizeLabel })
|
|
4258
|
+
]
|
|
4259
|
+
}
|
|
4260
|
+
);
|
|
4261
|
+
}
|
|
4201
4262
|
function AssistantMessage({
|
|
4202
4263
|
message,
|
|
4203
4264
|
isLast,
|
|
@@ -4338,6 +4399,25 @@ function Command({
|
|
|
4338
4399
|
}
|
|
4339
4400
|
);
|
|
4340
4401
|
}
|
|
4402
|
+
function CommandInput({
|
|
4403
|
+
className,
|
|
4404
|
+
...props
|
|
4405
|
+
}) {
|
|
4406
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "command-input-wrapper", className: "p-1", children: /* @__PURE__ */ jsxs(InputGroup, { className: "border-transparent border-b-input bg-transparent px-3", children: [
|
|
4407
|
+
/* @__PURE__ */ jsx(
|
|
4408
|
+
Command$1.Input,
|
|
4409
|
+
{
|
|
4410
|
+
"data-slot": "command-input",
|
|
4411
|
+
className: cn(
|
|
4412
|
+
"w-full px-2 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
|
4413
|
+
className
|
|
4414
|
+
),
|
|
4415
|
+
...props
|
|
4416
|
+
}
|
|
4417
|
+
),
|
|
4418
|
+
/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, { className: "size-3.5 shrink-0 opacity-50" }) })
|
|
4419
|
+
] }) });
|
|
4420
|
+
}
|
|
4341
4421
|
function CommandList({
|
|
4342
4422
|
className,
|
|
4343
4423
|
...props
|
|
@@ -4383,6 +4463,19 @@ function CommandGroup({
|
|
|
4383
4463
|
}
|
|
4384
4464
|
);
|
|
4385
4465
|
}
|
|
4466
|
+
function CommandSeparator({
|
|
4467
|
+
className,
|
|
4468
|
+
...props
|
|
4469
|
+
}) {
|
|
4470
|
+
return /* @__PURE__ */ jsx(
|
|
4471
|
+
Command$1.Separator,
|
|
4472
|
+
{
|
|
4473
|
+
"data-slot": "command-separator",
|
|
4474
|
+
className: cn("-mx-1.5 my-1.5 h-px bg-border/50", className),
|
|
4475
|
+
...props
|
|
4476
|
+
}
|
|
4477
|
+
);
|
|
4478
|
+
}
|
|
4386
4479
|
function CommandItem({
|
|
4387
4480
|
className,
|
|
4388
4481
|
children,
|
|
@@ -4552,7 +4645,8 @@ var PromptInputProvider = ({
|
|
|
4552
4645
|
id: nanoid(),
|
|
4553
4646
|
mediaType: file.type,
|
|
4554
4647
|
type: "file",
|
|
4555
|
-
url: URL.createObjectURL(file)
|
|
4648
|
+
url: URL.createObjectURL(file),
|
|
4649
|
+
file
|
|
4556
4650
|
}))
|
|
4557
4651
|
]);
|
|
4558
4652
|
}, []);
|
|
@@ -4734,7 +4828,8 @@ var PromptInput = ({
|
|
|
4734
4828
|
id: nanoid(),
|
|
4735
4829
|
mediaType: file.type,
|
|
4736
4830
|
type: "file",
|
|
4737
|
-
url: URL.createObjectURL(file)
|
|
4831
|
+
url: URL.createObjectURL(file),
|
|
4832
|
+
file
|
|
4738
4833
|
});
|
|
4739
4834
|
}
|
|
4740
4835
|
return [...prev, ...next];
|
|
@@ -4934,15 +5029,17 @@ var PromptInput = ({
|
|
|
4934
5029
|
}
|
|
4935
5030
|
try {
|
|
4936
5031
|
const convertedFiles = await Promise.all(
|
|
4937
|
-
files.map(async (
|
|
4938
|
-
|
|
4939
|
-
|
|
5032
|
+
files.map(async (entry) => {
|
|
5033
|
+
const isBlob = entry.url?.startsWith("blob:");
|
|
5034
|
+
const isImage = entry.mediaType?.startsWith("image/");
|
|
5035
|
+
if (isBlob && isImage && entry.url) {
|
|
5036
|
+
const dataUrl = await convertBlobUrlToDataUrl(entry.url);
|
|
4940
5037
|
return {
|
|
4941
|
-
...
|
|
4942
|
-
url: dataUrl ??
|
|
5038
|
+
...entry,
|
|
5039
|
+
url: dataUrl ?? entry.url
|
|
4943
5040
|
};
|
|
4944
5041
|
}
|
|
4945
|
-
return
|
|
5042
|
+
return entry;
|
|
4946
5043
|
})
|
|
4947
5044
|
);
|
|
4948
5045
|
const result = onSubmit({ files: convertedFiles, text }, event);
|
|
@@ -5245,7 +5342,7 @@ var Context = ({
|
|
|
5245
5342
|
() => ({ maxTokens, modelId, usage, usedTokens }),
|
|
5246
5343
|
[maxTokens, modelId, usage, usedTokens]
|
|
5247
5344
|
);
|
|
5248
|
-
return /* @__PURE__ */ jsx(ContextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(HoverCard, { closeDelay:
|
|
5345
|
+
return /* @__PURE__ */ jsx(ContextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(HoverCard, { closeDelay: 100, openDelay: 0, ...props }) });
|
|
5249
5346
|
};
|
|
5250
5347
|
var ContextIcon = () => {
|
|
5251
5348
|
const { usedTokens, maxTokens } = useContextValue();
|
|
@@ -5485,6 +5582,125 @@ var ContextCacheUsage = ({
|
|
|
5485
5582
|
}
|
|
5486
5583
|
);
|
|
5487
5584
|
};
|
|
5585
|
+
var itemVariants = cva(
|
|
5586
|
+
"group/item flex w-full flex-wrap items-center rounded-none border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
|
|
5587
|
+
{
|
|
5588
|
+
variants: {
|
|
5589
|
+
variant: {
|
|
5590
|
+
default: "border-transparent",
|
|
5591
|
+
outline: "border-border",
|
|
5592
|
+
muted: "border-transparent bg-muted/50"
|
|
5593
|
+
},
|
|
5594
|
+
size: {
|
|
5595
|
+
default: "gap-3.5 px-4 py-3.5",
|
|
5596
|
+
sm: "gap-3.5 px-3.5 py-3",
|
|
5597
|
+
xs: "gap-2.5 px-3 py-2.5 in-data-[slot=dropdown-menu-content]:p-0"
|
|
5598
|
+
}
|
|
5599
|
+
},
|
|
5600
|
+
defaultVariants: {
|
|
5601
|
+
variant: "default",
|
|
5602
|
+
size: "default"
|
|
5603
|
+
}
|
|
5604
|
+
}
|
|
5605
|
+
);
|
|
5606
|
+
function Item({
|
|
5607
|
+
className,
|
|
5608
|
+
variant = "default",
|
|
5609
|
+
size = "default",
|
|
5610
|
+
asChild = false,
|
|
5611
|
+
...props
|
|
5612
|
+
}) {
|
|
5613
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
5614
|
+
return /* @__PURE__ */ jsx(
|
|
5615
|
+
Comp,
|
|
5616
|
+
{
|
|
5617
|
+
"data-slot": "item",
|
|
5618
|
+
"data-variant": variant,
|
|
5619
|
+
"data-size": size,
|
|
5620
|
+
className: cn(itemVariants({ variant, size, className })),
|
|
5621
|
+
...props
|
|
5622
|
+
}
|
|
5623
|
+
);
|
|
5624
|
+
}
|
|
5625
|
+
var itemMediaVariants = cva(
|
|
5626
|
+
"flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
|
|
5627
|
+
{
|
|
5628
|
+
variants: {
|
|
5629
|
+
variant: {
|
|
5630
|
+
default: "bg-transparent",
|
|
5631
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
5632
|
+
image: "size-10 overflow-hidden rounded-none group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 group-data-[size=xs]/item:rounded-none [&_img]:size-full [&_img]:object-cover"
|
|
5633
|
+
}
|
|
5634
|
+
},
|
|
5635
|
+
defaultVariants: {
|
|
5636
|
+
variant: "default"
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
);
|
|
5640
|
+
function ItemMedia({
|
|
5641
|
+
className,
|
|
5642
|
+
variant = "default",
|
|
5643
|
+
...props
|
|
5644
|
+
}) {
|
|
5645
|
+
return /* @__PURE__ */ jsx(
|
|
5646
|
+
"div",
|
|
5647
|
+
{
|
|
5648
|
+
"data-slot": "item-media",
|
|
5649
|
+
"data-variant": variant,
|
|
5650
|
+
className: cn(itemMediaVariants({ variant, className })),
|
|
5651
|
+
...props
|
|
5652
|
+
}
|
|
5653
|
+
);
|
|
5654
|
+
}
|
|
5655
|
+
function ItemContent({ className, ...props }) {
|
|
5656
|
+
return /* @__PURE__ */ jsx(
|
|
5657
|
+
"div",
|
|
5658
|
+
{
|
|
5659
|
+
"data-slot": "item-content",
|
|
5660
|
+
className: cn(
|
|
5661
|
+
"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0.5 [&+[data-slot=item-content]]:flex-none",
|
|
5662
|
+
className
|
|
5663
|
+
),
|
|
5664
|
+
...props
|
|
5665
|
+
}
|
|
5666
|
+
);
|
|
5667
|
+
}
|
|
5668
|
+
function ItemTitle({ className, ...props }) {
|
|
5669
|
+
return /* @__PURE__ */ jsx(
|
|
5670
|
+
"div",
|
|
5671
|
+
{
|
|
5672
|
+
"data-slot": "item-title",
|
|
5673
|
+
className: cn(
|
|
5674
|
+
"line-clamp-1 flex w-fit items-center gap-2 text-xs leading-snug font-semibold uppercase underline-offset-4",
|
|
5675
|
+
className
|
|
5676
|
+
),
|
|
5677
|
+
...props
|
|
5678
|
+
}
|
|
5679
|
+
);
|
|
5680
|
+
}
|
|
5681
|
+
function ItemDescription({ className, ...props }) {
|
|
5682
|
+
return /* @__PURE__ */ jsx(
|
|
5683
|
+
"p",
|
|
5684
|
+
{
|
|
5685
|
+
"data-slot": "item-description",
|
|
5686
|
+
className: cn(
|
|
5687
|
+
"line-clamp-2 text-left text-sm leading-relaxed font-normal text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
|
|
5688
|
+
className
|
|
5689
|
+
),
|
|
5690
|
+
...props
|
|
5691
|
+
}
|
|
5692
|
+
);
|
|
5693
|
+
}
|
|
5694
|
+
function ItemActions({ className, ...props }) {
|
|
5695
|
+
return /* @__PURE__ */ jsx(
|
|
5696
|
+
"div",
|
|
5697
|
+
{
|
|
5698
|
+
"data-slot": "item-actions",
|
|
5699
|
+
className: cn("flex items-center gap-2", className),
|
|
5700
|
+
...props
|
|
5701
|
+
}
|
|
5702
|
+
);
|
|
5703
|
+
}
|
|
5488
5704
|
function Popover({
|
|
5489
5705
|
...props
|
|
5490
5706
|
}) {
|
|
@@ -5518,36 +5734,82 @@ function PopoverAnchor({
|
|
|
5518
5734
|
function ChatComposer(props) {
|
|
5519
5735
|
return /* @__PURE__ */ jsx(PromptInputProvider, { children: /* @__PURE__ */ jsx(ChatComposerInner, { ...props }) });
|
|
5520
5736
|
}
|
|
5737
|
+
function iconForMime2(mime) {
|
|
5738
|
+
if (!mime) return File$1;
|
|
5739
|
+
if (mime.startsWith("audio/")) return FileAudio;
|
|
5740
|
+
if (mime.startsWith("video/")) return FileVideo;
|
|
5741
|
+
if (mime === "application/pdf" || mime.startsWith("text/")) return FileText;
|
|
5742
|
+
if (mime === "application/json" || mime === "application/xml" || mime.endsWith("+xml") || mime.endsWith("+json") || mime.includes("javascript") || mime.includes("typescript")) {
|
|
5743
|
+
return FileCode;
|
|
5744
|
+
}
|
|
5745
|
+
if (mime === "application/zip" || mime === "application/x-7z-compressed" || mime === "application/x-tar" || mime === "application/gzip" || mime === "application/x-rar-compressed") {
|
|
5746
|
+
return FileArchive;
|
|
5747
|
+
}
|
|
5748
|
+
if (mime === "text/csv" || mime === "application/vnd.ms-excel" || mime.includes("spreadsheet")) {
|
|
5749
|
+
return FileSpreadsheet;
|
|
5750
|
+
}
|
|
5751
|
+
return File$1;
|
|
5752
|
+
}
|
|
5753
|
+
function formatBytes2(n) {
|
|
5754
|
+
if (n == null || !Number.isFinite(n) || n < 0) return "";
|
|
5755
|
+
for (const [unit, divisor] of [
|
|
5756
|
+
["GB", 1e9],
|
|
5757
|
+
["MB", 1e6],
|
|
5758
|
+
["KB", 1e3]
|
|
5759
|
+
]) {
|
|
5760
|
+
if (n >= divisor) return `${(n / divisor).toFixed(1)} ${unit}`;
|
|
5761
|
+
}
|
|
5762
|
+
return `${n} B`;
|
|
5763
|
+
}
|
|
5521
5764
|
function AttachmentPreviewStrip() {
|
|
5522
5765
|
const attachments = useProviderAttachments();
|
|
5523
5766
|
if (attachments.files.length === 0) return null;
|
|
5524
|
-
return /* @__PURE__ */ jsx("div", { className: "flex gap-2 px-3 pt-2 pb-1 flex-wrap", children: attachments.files.map((file) =>
|
|
5525
|
-
file.mediaType?.startsWith("image/") && file.url
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
className: "h-16 w-16 rounded-lg border border-border object-cover"
|
|
5531
|
-
}
|
|
5532
|
-
) : /* @__PURE__ */ jsx("div", { className: "h-16 w-16 rounded-lg border border-border bg-muted flex items-center justify-center text-[10px] text-muted-foreground truncate px-1", children: file.filename }),
|
|
5533
|
-
/* @__PURE__ */ jsx(
|
|
5534
|
-
"button",
|
|
5767
|
+
return /* @__PURE__ */ jsx("div", { className: "flex gap-2 px-3 pt-2 pb-1 flex-wrap", children: attachments.files.map((file) => {
|
|
5768
|
+
const isImage = file.mediaType?.startsWith("image/") && !!file.url;
|
|
5769
|
+
const sizeLabel = formatBytes2(file.file?.size);
|
|
5770
|
+
const Icon = iconForMime2(file.mediaType);
|
|
5771
|
+
return /* @__PURE__ */ jsxs(
|
|
5772
|
+
Item,
|
|
5535
5773
|
{
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
className: "
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5774
|
+
variant: "outline",
|
|
5775
|
+
size: "xs",
|
|
5776
|
+
className: "group w-auto max-w-[18rem] rounded-md",
|
|
5777
|
+
title: file.filename,
|
|
5778
|
+
children: [
|
|
5779
|
+
/* @__PURE__ */ jsx(ItemMedia, { variant: isImage ? "image" : "icon", children: isImage ? /* @__PURE__ */ jsx("img", { src: file.url, alt: file.filename }) : /* @__PURE__ */ jsx(Icon, {}) }),
|
|
5780
|
+
/* @__PURE__ */ jsxs(ItemContent, { className: "min-w-0", children: [
|
|
5781
|
+
/* @__PURE__ */ jsx(ItemTitle, { className: "block w-full truncate normal-case font-medium text-foreground", children: file.filename }),
|
|
5782
|
+
sizeLabel && /* @__PURE__ */ jsx(ItemDescription, { className: "text-xs", children: sizeLabel })
|
|
5783
|
+
] }),
|
|
5784
|
+
/* @__PURE__ */ jsx(ItemActions, { children: /* @__PURE__ */ jsx(
|
|
5785
|
+
"button",
|
|
5786
|
+
{
|
|
5787
|
+
type: "button",
|
|
5788
|
+
onClick: () => attachments.remove(file.id),
|
|
5789
|
+
"aria-label": `Remove ${file.filename}`,
|
|
5790
|
+
className: "hidden group-hover:flex items-center justify-center w-4 h-4 rounded-full bg-destructive text-destructive-foreground text-[10px]",
|
|
5791
|
+
children: "\xD7"
|
|
5792
|
+
}
|
|
5793
|
+
) })
|
|
5794
|
+
]
|
|
5795
|
+
},
|
|
5796
|
+
file.id
|
|
5797
|
+
);
|
|
5798
|
+
}) });
|
|
5543
5799
|
}
|
|
5800
|
+
var MAX_IMAGES_PER_MESSAGE = 5;
|
|
5801
|
+
var MAX_IMAGE_BYTES = 2e7;
|
|
5802
|
+
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
5803
|
+
var MAX_ATTACHMENT_BYTES = 5e7;
|
|
5804
|
+
var MAX_ATTACHMENTS_TOTAL_BYTES = 2e8;
|
|
5544
5805
|
function ChatComposerInner({
|
|
5545
5806
|
onSend,
|
|
5546
5807
|
onStop,
|
|
5547
5808
|
isRunning,
|
|
5548
5809
|
disabled = false,
|
|
5549
5810
|
disabledReason,
|
|
5550
|
-
tokenUsage
|
|
5811
|
+
tokenUsage,
|
|
5812
|
+
onComposerError
|
|
5551
5813
|
}) {
|
|
5552
5814
|
const { adapter } = useAgentChatAdapterContext();
|
|
5553
5815
|
const { textInput } = usePromptInputController();
|
|
@@ -5572,8 +5834,8 @@ function ChatComposerInner({
|
|
|
5572
5834
|
setWasClosed(true);
|
|
5573
5835
|
}
|
|
5574
5836
|
}, [adapter, showSlashMenu, wasClosed]);
|
|
5575
|
-
const
|
|
5576
|
-
|
|
5837
|
+
const builtinCommands = useMemo(
|
|
5838
|
+
() => [
|
|
5577
5839
|
{ value: "/clear", label: "/clear", description: "Clear conversation" },
|
|
5578
5840
|
{ value: "/compress", label: "/compress", description: "Compress context" },
|
|
5579
5841
|
{ value: "/goal", label: "/goal", description: "Define an outcome goal" },
|
|
@@ -5584,195 +5846,307 @@ function ChatComposerInner({
|
|
|
5584
5846
|
{ value: "/loop", label: "/loop", description: "Schedule recurring prompt" },
|
|
5585
5847
|
{ value: "/loop list", label: "/loop list", description: "List active loops" },
|
|
5586
5848
|
{ value: "/loop cancel", label: "/loop cancel", description: "Cancel a loop by ID" }
|
|
5587
|
-
]
|
|
5588
|
-
|
|
5589
|
-
}, [adapterCommands]);
|
|
5590
|
-
const searchQuery = showSlashMenu ? textInput.value.slice(1).toLowerCase() : "";
|
|
5591
|
-
const filteredCommands = useMemo(
|
|
5592
|
-
() => slashCommands.filter(
|
|
5593
|
-
(cmd) => cmd.value.slice(1).toLowerCase().includes(searchQuery) || cmd.description.toLowerCase().includes(searchQuery)
|
|
5594
|
-
),
|
|
5595
|
-
[slashCommands, searchQuery]
|
|
5849
|
+
],
|
|
5850
|
+
[]
|
|
5596
5851
|
);
|
|
5597
|
-
const
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
(
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5852
|
+
const searchQuery = showSlashMenu ? textInput.value.slice(1) : "";
|
|
5853
|
+
const menuOpen = showSlashMenu;
|
|
5854
|
+
const textareaRef = useRef(null);
|
|
5855
|
+
const focusTextareaAtEnd = useCallback(() => {
|
|
5856
|
+
requestAnimationFrame(() => {
|
|
5857
|
+
const textarea = textareaRef.current;
|
|
5858
|
+
if (!textarea) return;
|
|
5859
|
+
textarea.focus();
|
|
5860
|
+
const end = textarea.value.length;
|
|
5861
|
+
textarea.setSelectionRange(end, end);
|
|
5862
|
+
});
|
|
5863
|
+
}, []);
|
|
5607
5864
|
const handleCommandSelect = useCallback(
|
|
5608
5865
|
(commandValue) => {
|
|
5609
5866
|
textInput.setInput(commandValue + " ");
|
|
5610
5867
|
setButtonMenuOpen(false);
|
|
5611
5868
|
setMenuDismissed(true);
|
|
5869
|
+
focusTextareaAtEnd();
|
|
5612
5870
|
},
|
|
5613
|
-
[textInput]
|
|
5871
|
+
[textInput, focusTextareaAtEnd]
|
|
5614
5872
|
);
|
|
5615
|
-
const
|
|
5616
|
-
(
|
|
5617
|
-
|
|
5618
|
-
if (e.key === "ArrowDown") {
|
|
5619
|
-
e.preventDefault();
|
|
5620
|
-
setSelectedIndex((i) => Math.min(i + 1, filteredCommands.length - 1));
|
|
5621
|
-
} else if (e.key === "ArrowUp") {
|
|
5622
|
-
e.preventDefault();
|
|
5623
|
-
setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
5624
|
-
} else if (e.key === "Enter") {
|
|
5625
|
-
e.preventDefault();
|
|
5626
|
-
const command = filteredCommands[selectedIndex];
|
|
5627
|
-
if (command) handleCommandSelect(command.value);
|
|
5628
|
-
} else if (e.key === "Escape") {
|
|
5629
|
-
e.preventDefault();
|
|
5630
|
-
textInput.setInput("");
|
|
5631
|
-
setButtonMenuOpen(false);
|
|
5632
|
-
setMenuDismissed(true);
|
|
5633
|
-
} else if (e.key === "Tab") {
|
|
5634
|
-
e.preventDefault();
|
|
5635
|
-
const command = filteredCommands[selectedIndex];
|
|
5636
|
-
if (command) handleCommandSelect(command.value);
|
|
5637
|
-
}
|
|
5873
|
+
const handleSearchChange = useCallback(
|
|
5874
|
+
(next) => {
|
|
5875
|
+
textInput.setInput("/" + next);
|
|
5638
5876
|
},
|
|
5639
|
-
[
|
|
5877
|
+
[textInput]
|
|
5640
5878
|
);
|
|
5641
5879
|
const handleSubmit = useCallback(
|
|
5642
5880
|
async (message) => {
|
|
5643
5881
|
const text = message.text.trim();
|
|
5644
5882
|
if (!text || disabled) return;
|
|
5645
5883
|
const images = [];
|
|
5884
|
+
const pending = [];
|
|
5646
5885
|
for (const file of message.files) {
|
|
5647
5886
|
if (file.mediaType?.startsWith("image/") && file.url) {
|
|
5648
5887
|
images.push({ data: file.url, mimeType: file.mediaType });
|
|
5888
|
+
continue;
|
|
5649
5889
|
}
|
|
5890
|
+
if (!file.file) {
|
|
5891
|
+
continue;
|
|
5892
|
+
}
|
|
5893
|
+
pending.push({
|
|
5894
|
+
file: file.file,
|
|
5895
|
+
filename: file.filename ?? file.file.name,
|
|
5896
|
+
mimeType: file.mediaType ?? file.file.type ?? void 0,
|
|
5897
|
+
size: file.file.size
|
|
5898
|
+
});
|
|
5899
|
+
}
|
|
5900
|
+
if (images.length > MAX_IMAGES_PER_MESSAGE) {
|
|
5901
|
+
onComposerError?.({
|
|
5902
|
+
code: "max_images",
|
|
5903
|
+
message: `Maximum ${MAX_IMAGES_PER_MESSAGE} images per message.`
|
|
5904
|
+
});
|
|
5905
|
+
return;
|
|
5906
|
+
}
|
|
5907
|
+
if (pending.length > MAX_ATTACHMENTS_PER_MESSAGE) {
|
|
5908
|
+
onComposerError?.({
|
|
5909
|
+
code: "max_attachments",
|
|
5910
|
+
message: `Maximum ${MAX_ATTACHMENTS_PER_MESSAGE} attachments per message.`
|
|
5911
|
+
});
|
|
5912
|
+
return;
|
|
5913
|
+
}
|
|
5914
|
+
for (const img of images) {
|
|
5915
|
+
if (img.data.length > Math.ceil(MAX_IMAGE_BYTES * 4 / 3)) {
|
|
5916
|
+
onComposerError?.({
|
|
5917
|
+
code: "max_image_size",
|
|
5918
|
+
message: `Image exceeds ${MAX_IMAGE_BYTES / 1e6} MB.`
|
|
5919
|
+
});
|
|
5920
|
+
return;
|
|
5921
|
+
}
|
|
5922
|
+
}
|
|
5923
|
+
let totalAttachmentBytes = 0;
|
|
5924
|
+
for (const a of pending) {
|
|
5925
|
+
if (a.file.size > MAX_ATTACHMENT_BYTES) {
|
|
5926
|
+
onComposerError?.({
|
|
5927
|
+
code: "max_attachment_size",
|
|
5928
|
+
message: `"${a.filename}" exceeds ${MAX_ATTACHMENT_BYTES / 1e6} MB.`
|
|
5929
|
+
});
|
|
5930
|
+
return;
|
|
5931
|
+
}
|
|
5932
|
+
totalAttachmentBytes += a.file.size;
|
|
5933
|
+
}
|
|
5934
|
+
if (totalAttachmentBytes > MAX_ATTACHMENTS_TOTAL_BYTES) {
|
|
5935
|
+
onComposerError?.({
|
|
5936
|
+
code: "max_attachments_total",
|
|
5937
|
+
message: `Attachments exceed ${MAX_ATTACHMENTS_TOTAL_BYTES / 1e6} MB total for this message.`
|
|
5938
|
+
});
|
|
5939
|
+
return;
|
|
5650
5940
|
}
|
|
5651
5941
|
if (isRunning) {
|
|
5652
5942
|
await onStop();
|
|
5653
5943
|
}
|
|
5654
|
-
await onSend(
|
|
5944
|
+
await onSend(
|
|
5945
|
+
text,
|
|
5946
|
+
images.length > 0 ? images : void 0,
|
|
5947
|
+
pending.length > 0 ? pending : void 0
|
|
5948
|
+
);
|
|
5655
5949
|
},
|
|
5656
|
-
[onSend, onStop, isRunning, disabled]
|
|
5950
|
+
[onSend, onStop, onComposerError, isRunning, disabled]
|
|
5657
5951
|
);
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5952
|
+
const handlePromptInputError = useCallback(
|
|
5953
|
+
(err) => {
|
|
5954
|
+
onComposerError?.({ code: err.code, message: err.message });
|
|
5955
|
+
},
|
|
5956
|
+
[onComposerError]
|
|
5957
|
+
);
|
|
5958
|
+
return /* @__PURE__ */ jsxs(
|
|
5959
|
+
Popover,
|
|
5960
|
+
{
|
|
5961
|
+
open: menuOpen,
|
|
5962
|
+
onOpenChange: (open) => {
|
|
5963
|
+
if (!open) {
|
|
5964
|
+
setButtonMenuOpen(false);
|
|
5965
|
+
setMenuDismissed(true);
|
|
5671
5966
|
}
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
/* @__PURE__ */
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
modelId: tokenUsage.model,
|
|
5700
|
-
usage: {
|
|
5701
|
-
inputTokens: tokenUsage.inputTokens,
|
|
5702
|
-
outputTokens: tokenUsage.outputTokens,
|
|
5703
|
-
reasoningTokens: tokenUsage.reasoningTokens,
|
|
5704
|
-
cachedInputTokens: tokenUsage.cachedInputTokens,
|
|
5705
|
-
totalTokens: tokenUsage.totalTokens,
|
|
5706
|
-
inputTokenDetails: void 0,
|
|
5707
|
-
outputTokenDetails: void 0
|
|
5708
|
-
},
|
|
5709
|
-
children: [
|
|
5710
|
-
/* @__PURE__ */ jsx(ContextTrigger, {}),
|
|
5711
|
-
/* @__PURE__ */ jsxs(ContextContent, { children: [
|
|
5712
|
-
/* @__PURE__ */ jsx(ContextContentHeader, {}),
|
|
5713
|
-
/* @__PURE__ */ jsx(ContextContentBody, { children: tokenUsage.totalTokens > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5714
|
-
/* @__PURE__ */ jsx(ContextInputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
5715
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Input" }),
|
|
5716
|
-
/* @__PURE__ */ jsx("span", { children: tokenUsage.inputTokens.toLocaleString() })
|
|
5717
|
-
] }) }),
|
|
5718
|
-
/* @__PURE__ */ jsx(ContextOutputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
5719
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Output" }),
|
|
5720
|
-
/* @__PURE__ */ jsx("span", { children: tokenUsage.outputTokens.toLocaleString() })
|
|
5721
|
-
] }) }),
|
|
5722
|
-
tokenUsage.reasoningTokens > 0 && /* @__PURE__ */ jsx(ContextReasoningUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
5723
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
|
|
5724
|
-
/* @__PURE__ */ jsx("span", { children: tokenUsage.reasoningTokens.toLocaleString() })
|
|
5725
|
-
] }) }),
|
|
5726
|
-
tokenUsage.cachedInputTokens > 0 && /* @__PURE__ */ jsx(ContextCacheUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
5727
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cache" }),
|
|
5728
|
-
/* @__PURE__ */ jsx("span", { children: tokenUsage.cachedInputTokens.toLocaleString() })
|
|
5729
|
-
] }) })
|
|
5730
|
-
] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-1", children: "Empty" }) }),
|
|
5731
|
-
tokenUsage.totalTokens > 0 && /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end gap-3 bg-secondary p-3", children: /* @__PURE__ */ jsx(
|
|
5967
|
+
},
|
|
5968
|
+
children: [
|
|
5969
|
+
/* @__PURE__ */ jsx(AttachmentPreviewStrip, {}),
|
|
5970
|
+
/* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
5971
|
+
PromptInput,
|
|
5972
|
+
{
|
|
5973
|
+
onSubmit: handleSubmit,
|
|
5974
|
+
multiple: true,
|
|
5975
|
+
maxFiles: MAX_IMAGES_PER_MESSAGE + MAX_ATTACHMENTS_PER_MESSAGE,
|
|
5976
|
+
maxFileSize: MAX_ATTACHMENT_BYTES,
|
|
5977
|
+
onError: handlePromptInputError,
|
|
5978
|
+
children: [
|
|
5979
|
+
/* @__PURE__ */ jsx(PromptInputBody, { children: /* @__PURE__ */ jsx(
|
|
5980
|
+
PromptInputTextarea,
|
|
5981
|
+
{
|
|
5982
|
+
ref: textareaRef,
|
|
5983
|
+
placeholder: disabled ? disabledReason ?? "Session disabled" : "Send a message...",
|
|
5984
|
+
disabled
|
|
5985
|
+
}
|
|
5986
|
+
) }),
|
|
5987
|
+
/* @__PURE__ */ jsxs(PromptInputFooter, { children: [
|
|
5988
|
+
/* @__PURE__ */ jsxs(PromptInputTools, { children: [
|
|
5989
|
+
/* @__PURE__ */ jsxs(PromptInputActionMenu, { children: [
|
|
5990
|
+
/* @__PURE__ */ jsx(PromptInputActionMenuTrigger, {}),
|
|
5991
|
+
/* @__PURE__ */ jsx(PromptInputActionMenuContent, { children: /* @__PURE__ */ jsx(PromptInputActionAddAttachments, {}) })
|
|
5992
|
+
] }),
|
|
5993
|
+
/* @__PURE__ */ jsx(
|
|
5732
5994
|
Button,
|
|
5733
5995
|
{
|
|
5734
5996
|
type: "button",
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5997
|
+
variant: "ghost",
|
|
5998
|
+
size: "icon-xs",
|
|
5999
|
+
className: "text-muted-foreground",
|
|
6000
|
+
onClick: (e) => {
|
|
6001
|
+
e.preventDefault();
|
|
6002
|
+
setButtonMenuOpen((v) => !v);
|
|
6003
|
+
},
|
|
6004
|
+
"aria-label": "Slash commands",
|
|
6005
|
+
children: /* @__PURE__ */ jsx("span", { className: "text-xs font-bold", children: "/" })
|
|
5738
6006
|
}
|
|
5739
|
-
)
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
6007
|
+
),
|
|
6008
|
+
tokenUsage && tokenUsage.contextWindow > 0 && /* @__PURE__ */ jsxs(
|
|
6009
|
+
Context,
|
|
6010
|
+
{
|
|
6011
|
+
usedTokens: tokenUsage.totalTokens,
|
|
6012
|
+
maxTokens: tokenUsage.contextWindow,
|
|
6013
|
+
modelId: tokenUsage.model,
|
|
6014
|
+
usage: {
|
|
6015
|
+
inputTokens: tokenUsage.inputTokens,
|
|
6016
|
+
outputTokens: tokenUsage.outputTokens,
|
|
6017
|
+
reasoningTokens: tokenUsage.reasoningTokens,
|
|
6018
|
+
cachedInputTokens: tokenUsage.cachedInputTokens,
|
|
6019
|
+
totalTokens: tokenUsage.totalTokens,
|
|
6020
|
+
inputTokenDetails: void 0,
|
|
6021
|
+
outputTokenDetails: void 0
|
|
6022
|
+
},
|
|
6023
|
+
children: [
|
|
6024
|
+
/* @__PURE__ */ jsx(ContextTrigger, {}),
|
|
6025
|
+
/* @__PURE__ */ jsxs(ContextContent, { children: [
|
|
6026
|
+
/* @__PURE__ */ jsx(ContextContentHeader, {}),
|
|
6027
|
+
/* @__PURE__ */ jsx(ContextContentBody, { children: tokenUsage.totalTokens > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6028
|
+
/* @__PURE__ */ jsx(ContextInputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6029
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Input" }),
|
|
6030
|
+
/* @__PURE__ */ jsx("span", { children: tokenUsage.inputTokens.toLocaleString() })
|
|
6031
|
+
] }) }),
|
|
6032
|
+
/* @__PURE__ */ jsx(ContextOutputUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6033
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Output" }),
|
|
6034
|
+
/* @__PURE__ */ jsx("span", { children: tokenUsage.outputTokens.toLocaleString() })
|
|
6035
|
+
] }) }),
|
|
6036
|
+
tokenUsage.reasoningTokens > 0 && /* @__PURE__ */ jsx(ContextReasoningUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6037
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Reasoning" }),
|
|
6038
|
+
/* @__PURE__ */ jsx("span", { children: tokenUsage.reasoningTokens.toLocaleString() })
|
|
6039
|
+
] }) }),
|
|
6040
|
+
tokenUsage.cachedInputTokens > 0 && /* @__PURE__ */ jsx(ContextCacheUsage, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs", children: [
|
|
6041
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Cache" }),
|
|
6042
|
+
/* @__PURE__ */ jsx("span", { children: tokenUsage.cachedInputTokens.toLocaleString() })
|
|
6043
|
+
] }) })
|
|
6044
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-1", children: "Empty" }) }),
|
|
6045
|
+
tokenUsage.totalTokens > 0 && /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-end gap-3 bg-secondary p-2", children: /* @__PURE__ */ jsx(
|
|
6046
|
+
Button,
|
|
6047
|
+
{
|
|
6048
|
+
type: "button",
|
|
6049
|
+
size: "xs",
|
|
6050
|
+
onClick: () => onSend("/compress"),
|
|
6051
|
+
children: "Compress"
|
|
6052
|
+
}
|
|
6053
|
+
) })
|
|
6054
|
+
] })
|
|
6055
|
+
]
|
|
6056
|
+
}
|
|
6057
|
+
)
|
|
6058
|
+
] }),
|
|
6059
|
+
/* @__PURE__ */ jsx(PromptInputSubmit, { status, onStop })
|
|
6060
|
+
] })
|
|
6061
|
+
]
|
|
6062
|
+
}
|
|
6063
|
+
) }),
|
|
6064
|
+
/* @__PURE__ */ jsx(
|
|
6065
|
+
PopoverContent,
|
|
6066
|
+
{
|
|
6067
|
+
side: "top",
|
|
6068
|
+
align: "start",
|
|
6069
|
+
className: "overflow-hidden p-0",
|
|
6070
|
+
style: { width: "var(--radix-popover-trigger-width)" },
|
|
6071
|
+
onCloseAutoFocus: (e) => e.preventDefault(),
|
|
6072
|
+
onEscapeKeyDown: () => {
|
|
6073
|
+
focusTextareaAtEnd();
|
|
5768
6074
|
},
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
6075
|
+
children: /* @__PURE__ */ jsxs(Command, { children: [
|
|
6076
|
+
/* @__PURE__ */ jsx(
|
|
6077
|
+
CommandInput,
|
|
6078
|
+
{
|
|
6079
|
+
placeholder: "Type a command or search...",
|
|
6080
|
+
value: searchQuery,
|
|
6081
|
+
onValueChange: handleSearchChange
|
|
6082
|
+
}
|
|
6083
|
+
),
|
|
6084
|
+
/* @__PURE__ */ jsxs(CommandList, { children: [
|
|
6085
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: "No commands found." }),
|
|
6086
|
+
builtinCommands.length > 0 && /* @__PURE__ */ jsx(CommandGroup, { heading: "Built-in commands", children: builtinCommands.map((cmd) => /* @__PURE__ */ jsxs(
|
|
6087
|
+
CommandItem,
|
|
6088
|
+
{
|
|
6089
|
+
value: cmd.value,
|
|
6090
|
+
keywords: [cmd.description],
|
|
6091
|
+
onSelect: () => handleCommandSelect(cmd.value),
|
|
6092
|
+
className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
|
|
6093
|
+
children: [
|
|
6094
|
+
/* @__PURE__ */ jsx(
|
|
6095
|
+
"span",
|
|
6096
|
+
{
|
|
6097
|
+
className: "font-mono text-foreground truncate",
|
|
6098
|
+
title: cmd.label,
|
|
6099
|
+
children: cmd.label
|
|
6100
|
+
}
|
|
6101
|
+
),
|
|
6102
|
+
/* @__PURE__ */ jsx(
|
|
6103
|
+
"span",
|
|
6104
|
+
{
|
|
6105
|
+
className: "min-w-0 truncate text-xs text-muted-foreground",
|
|
6106
|
+
title: cmd.description,
|
|
6107
|
+
children: cmd.description
|
|
6108
|
+
}
|
|
6109
|
+
)
|
|
6110
|
+
]
|
|
6111
|
+
},
|
|
6112
|
+
cmd.value
|
|
6113
|
+
)) }),
|
|
6114
|
+
builtinCommands.length > 0 && adapterCommands.length > 0 && /* @__PURE__ */ jsx(CommandSeparator, {}),
|
|
6115
|
+
adapterCommands.length > 0 && /* @__PURE__ */ jsx(CommandGroup, { heading: "Skills", children: adapterCommands.map((cmd) => /* @__PURE__ */ jsxs(
|
|
6116
|
+
CommandItem,
|
|
6117
|
+
{
|
|
6118
|
+
value: cmd.value,
|
|
6119
|
+
keywords: [cmd.description],
|
|
6120
|
+
onSelect: () => handleCommandSelect(cmd.value),
|
|
6121
|
+
className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
|
|
6122
|
+
children: [
|
|
6123
|
+
/* @__PURE__ */ jsx(
|
|
6124
|
+
"span",
|
|
6125
|
+
{
|
|
6126
|
+
className: "font-mono text-foreground truncate",
|
|
6127
|
+
title: cmd.label,
|
|
6128
|
+
children: cmd.label
|
|
6129
|
+
}
|
|
6130
|
+
),
|
|
6131
|
+
/* @__PURE__ */ jsx(
|
|
6132
|
+
"span",
|
|
6133
|
+
{
|
|
6134
|
+
className: "min-w-0 truncate text-xs text-muted-foreground",
|
|
6135
|
+
title: cmd.description,
|
|
6136
|
+
children: cmd.description
|
|
6137
|
+
}
|
|
6138
|
+
)
|
|
6139
|
+
]
|
|
6140
|
+
},
|
|
6141
|
+
cmd.value
|
|
6142
|
+
)) })
|
|
6143
|
+
] })
|
|
6144
|
+
] })
|
|
6145
|
+
}
|
|
6146
|
+
)
|
|
6147
|
+
]
|
|
6148
|
+
}
|
|
6149
|
+
);
|
|
5776
6150
|
}
|
|
5777
6151
|
var Artifact = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
5778
6152
|
"div",
|
|
@@ -6748,7 +7122,8 @@ function ChatThread({
|
|
|
6748
7122
|
disabledReason,
|
|
6749
7123
|
tokenUsage,
|
|
6750
7124
|
retryIndicator,
|
|
6751
|
-
onRetry
|
|
7125
|
+
onRetry,
|
|
7126
|
+
onComposerError
|
|
6752
7127
|
}) {
|
|
6753
7128
|
const groups = useMemo(() => groupMessages(messages), [messages]);
|
|
6754
7129
|
const artifactFallbacks = useMemo(() => {
|
|
@@ -6865,7 +7240,8 @@ function ChatThread({
|
|
|
6865
7240
|
isRunning,
|
|
6866
7241
|
disabled,
|
|
6867
7242
|
disabledReason,
|
|
6868
|
-
tokenUsage
|
|
7243
|
+
tokenUsage,
|
|
7244
|
+
onComposerError
|
|
6869
7245
|
}
|
|
6870
7246
|
)
|
|
6871
7247
|
] })
|
|
@@ -8174,12 +8550,24 @@ function applyRetryIndicator(state, event) {
|
|
|
8174
8550
|
}
|
|
8175
8551
|
function applyUserMessage(messages, eventId, data) {
|
|
8176
8552
|
const content = stringValue2(data.content);
|
|
8553
|
+
const images = parseUserMessageImages(data.images);
|
|
8554
|
+
const attachments = parseUserMessageAttachments(data.attachments);
|
|
8177
8555
|
const next = [...messages];
|
|
8178
8556
|
const localIdx = next.findIndex(
|
|
8179
8557
|
(m) => m.role === "user" && m.id.startsWith("local-") && m.content === content
|
|
8180
8558
|
);
|
|
8181
8559
|
if (localIdx >= 0) {
|
|
8182
|
-
|
|
8560
|
+
const local = next[localIdx];
|
|
8561
|
+
next[localIdx] = {
|
|
8562
|
+
...local,
|
|
8563
|
+
id: `evt-${eventId}`,
|
|
8564
|
+
// Server-confirmed lists replace any optimistic display-only
|
|
8565
|
+
// entries: chips that were rendered while the upload was in
|
|
8566
|
+
// flight become clickable because the persisted refs include a
|
|
8567
|
+
// workspace path.
|
|
8568
|
+
images: images ?? local.images,
|
|
8569
|
+
attachments: attachments ?? local.attachments
|
|
8570
|
+
};
|
|
8183
8571
|
return next;
|
|
8184
8572
|
}
|
|
8185
8573
|
next.push({
|
|
@@ -8187,10 +8575,41 @@ function applyUserMessage(messages, eventId, data) {
|
|
|
8187
8575
|
role: "user",
|
|
8188
8576
|
content,
|
|
8189
8577
|
createdAt: /* @__PURE__ */ new Date(),
|
|
8190
|
-
status: "complete"
|
|
8578
|
+
status: "complete",
|
|
8579
|
+
images,
|
|
8580
|
+
attachments
|
|
8191
8581
|
});
|
|
8192
8582
|
return next;
|
|
8193
8583
|
}
|
|
8584
|
+
function parseUserMessageImages(raw) {
|
|
8585
|
+
if (!Array.isArray(raw)) return void 0;
|
|
8586
|
+
const out = [];
|
|
8587
|
+
for (const item of raw) {
|
|
8588
|
+
if (!item || typeof item !== "object") continue;
|
|
8589
|
+
const r = item;
|
|
8590
|
+
const data = typeof r.data === "string" ? r.data : void 0;
|
|
8591
|
+
if (!data) continue;
|
|
8592
|
+
const mimeType = typeof r.mime_type === "string" ? r.mime_type : typeof r.mimeType === "string" ? r.mimeType : void 0;
|
|
8593
|
+
out.push({ data, mimeType });
|
|
8594
|
+
}
|
|
8595
|
+
return out.length > 0 ? out : void 0;
|
|
8596
|
+
}
|
|
8597
|
+
function parseUserMessageAttachments(raw) {
|
|
8598
|
+
if (!Array.isArray(raw)) return void 0;
|
|
8599
|
+
const out = [];
|
|
8600
|
+
for (const item of raw) {
|
|
8601
|
+
if (!item || typeof item !== "object") continue;
|
|
8602
|
+
const r = item;
|
|
8603
|
+
const filename = typeof r.filename === "string" ? r.filename : void 0;
|
|
8604
|
+
if (!filename) continue;
|
|
8605
|
+
const path = typeof r.path === "string" ? r.path : void 0;
|
|
8606
|
+
if (!path) continue;
|
|
8607
|
+
const mimeType = typeof r.mime_type === "string" ? r.mime_type : typeof r.mimeType === "string" ? r.mimeType : void 0;
|
|
8608
|
+
const size = typeof r.size === "number" ? r.size : void 0;
|
|
8609
|
+
out.push({ path, filename, mimeType, size });
|
|
8610
|
+
}
|
|
8611
|
+
return out.length > 0 ? out : void 0;
|
|
8612
|
+
}
|
|
8194
8613
|
function applyBrowserEvent(state, event, browser) {
|
|
8195
8614
|
return withMessages(
|
|
8196
8615
|
{ ...state, browser },
|
|
@@ -8762,7 +9181,7 @@ function useAgentChatRuntime({
|
|
|
8762
9181
|
};
|
|
8763
9182
|
}, [adapter, clearReconnectTimer, closeStream, openStream, sessionId]);
|
|
8764
9183
|
const markSending = useCallback(
|
|
8765
|
-
(content, images) => {
|
|
9184
|
+
(content, images, attachments) => {
|
|
8766
9185
|
setState((prev) => ({
|
|
8767
9186
|
...prev,
|
|
8768
9187
|
terminal: false,
|
|
@@ -8776,7 +9195,8 @@ function useAgentChatRuntime({
|
|
|
8776
9195
|
content,
|
|
8777
9196
|
createdAt: /* @__PURE__ */ new Date(),
|
|
8778
9197
|
status: "complete",
|
|
8779
|
-
images: images?.length ? images : void 0
|
|
9198
|
+
images: images?.length ? images : void 0,
|
|
9199
|
+
attachments: attachments?.length ? attachments : void 0
|
|
8780
9200
|
}
|
|
8781
9201
|
]
|
|
8782
9202
|
}));
|
|
@@ -8833,14 +9253,48 @@ function useAgentChatRuntime({
|
|
|
8833
9253
|
});
|
|
8834
9254
|
}, []);
|
|
8835
9255
|
const send = useCallback(
|
|
8836
|
-
async (content, images) => {
|
|
8837
|
-
|
|
8838
|
-
|
|
9256
|
+
async (content, images, pendingAttachments) => {
|
|
9257
|
+
const displayAttachments = pendingAttachments?.length ? pendingAttachments.map((a) => ({
|
|
9258
|
+
filename: a.filename,
|
|
9259
|
+
mimeType: a.mimeType,
|
|
9260
|
+
size: a.size ?? a.file.size
|
|
9261
|
+
// path absent until upload completes.
|
|
9262
|
+
})) : void 0;
|
|
9263
|
+
markSending(content, images, displayAttachments);
|
|
9264
|
+
const goal = images?.length || pendingAttachments?.length ? null : parseGoalDefinition(content);
|
|
9265
|
+
const runUploadsAndSend = async (sid) => {
|
|
9266
|
+
let refs;
|
|
9267
|
+
if (pendingAttachments?.length) {
|
|
9268
|
+
const stamp = Date.now();
|
|
9269
|
+
refs = await Promise.all(
|
|
9270
|
+
pendingAttachments.map(async (a, index) => {
|
|
9271
|
+
const safeName = sanitizeUploadFilename(a.file.name);
|
|
9272
|
+
const renamed = new File(
|
|
9273
|
+
[a.file],
|
|
9274
|
+
`${stamp}-${index}-${safeName}`,
|
|
9275
|
+
{ type: a.file.type }
|
|
9276
|
+
);
|
|
9277
|
+
const up = await adapter.uploadWorkspaceFile({
|
|
9278
|
+
sessionId: sid,
|
|
9279
|
+
file: renamed,
|
|
9280
|
+
directory: "uploads"
|
|
9281
|
+
});
|
|
9282
|
+
return {
|
|
9283
|
+
path: up.path,
|
|
9284
|
+
filename: a.filename,
|
|
9285
|
+
mimeType: a.mimeType ?? a.file.type ?? void 0,
|
|
9286
|
+
size: up.size
|
|
9287
|
+
};
|
|
9288
|
+
})
|
|
9289
|
+
);
|
|
9290
|
+
}
|
|
9291
|
+
await sendTurn(adapter, sid, content, images, refs, goal);
|
|
9292
|
+
};
|
|
8839
9293
|
if (!sessionId) {
|
|
8840
9294
|
try {
|
|
8841
9295
|
const session2 = await adapter.createSession({ agentId });
|
|
8842
9296
|
onSessionChange?.(session2.id);
|
|
8843
|
-
await
|
|
9297
|
+
await runUploadsAndSend(session2.id);
|
|
8844
9298
|
} catch (error) {
|
|
8845
9299
|
markSendError(error instanceof Error ? error.message : "send failed");
|
|
8846
9300
|
throw error;
|
|
@@ -8849,7 +9303,7 @@ function useAgentChatRuntime({
|
|
|
8849
9303
|
}
|
|
8850
9304
|
try {
|
|
8851
9305
|
ensureStreamForNewTurn(sessionId);
|
|
8852
|
-
await
|
|
9306
|
+
await runUploadsAndSend(sessionId);
|
|
8853
9307
|
} catch (error) {
|
|
8854
9308
|
markSendError(error instanceof Error ? error.message : "send failed");
|
|
8855
9309
|
throw error;
|
|
@@ -8924,7 +9378,7 @@ function findLastAssistantIndex2(messages) {
|
|
|
8924
9378
|
}
|
|
8925
9379
|
var GOAL_RUBRIC_RE = /\n\s*(?:rubric|criteria)\s*:\s*\n/i;
|
|
8926
9380
|
var GOAL_CONTROL_COMMANDS = /* @__PURE__ */ new Set(["", "status", "pause", "resume", "clear"]);
|
|
8927
|
-
async function sendTurn(adapter, sessionId, content, images, goal) {
|
|
9381
|
+
async function sendTurn(adapter, sessionId, content, images, attachments, goal) {
|
|
8928
9382
|
if (goal && adapter.defineOutcome) {
|
|
8929
9383
|
await adapter.defineOutcome({
|
|
8930
9384
|
sessionId,
|
|
@@ -8933,7 +9387,11 @@ async function sendTurn(adapter, sessionId, content, images, goal) {
|
|
|
8933
9387
|
});
|
|
8934
9388
|
return;
|
|
8935
9389
|
}
|
|
8936
|
-
await adapter.sendMessage({ sessionId, content, images });
|
|
9390
|
+
await adapter.sendMessage({ sessionId, content, images, attachments });
|
|
9391
|
+
}
|
|
9392
|
+
function sanitizeUploadFilename(name) {
|
|
9393
|
+
const stripped = name.replace(/[\/\\\0]/g, "").trim();
|
|
9394
|
+
return stripped.length > 0 ? stripped : "attachment";
|
|
8937
9395
|
}
|
|
8938
9396
|
function parseGoalDefinition(content) {
|
|
8939
9397
|
const text = content.trim();
|
|
@@ -8953,7 +9411,8 @@ function AgentChat({
|
|
|
8953
9411
|
onSessionChange,
|
|
8954
9412
|
onFileSelect,
|
|
8955
9413
|
onMessagesChange,
|
|
8956
|
-
disabled
|
|
9414
|
+
disabled,
|
|
9415
|
+
onComposerError
|
|
8957
9416
|
}) {
|
|
8958
9417
|
const [workspacePath, setWorkspacePath] = useState(null);
|
|
8959
9418
|
const runtime = useAgentChatRuntime({
|
|
@@ -9005,14 +9464,15 @@ function AgentChat({
|
|
|
9005
9464
|
messages: runtime.messages,
|
|
9006
9465
|
isRunning: runtime.isRunning,
|
|
9007
9466
|
isLoadingHistory: runtime.isLoadingHistory,
|
|
9008
|
-
onSend: (content, images) => runtime.send(content, images),
|
|
9467
|
+
onSend: (content, images, attachments) => runtime.send(content, images, attachments),
|
|
9009
9468
|
onStop: () => runtime.stop(),
|
|
9010
9469
|
onRetry: runtime.retry,
|
|
9011
9470
|
onFileSelect: handleFileSelect,
|
|
9012
9471
|
disabled: effectiveDisabled,
|
|
9013
9472
|
disabledReason,
|
|
9014
9473
|
tokenUsage: runtime.tokenUsage,
|
|
9015
|
-
retryIndicator: runtime.retryIndicator
|
|
9474
|
+
retryIndicator: runtime.retryIndicator,
|
|
9475
|
+
onComposerError
|
|
9016
9476
|
}
|
|
9017
9477
|
)
|
|
9018
9478
|
}
|