@cntyclub/agent-react 0.18.0 → 0.19.0
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/components/agent-panel.d.ts.map +1 -1
- package/dist/components/agent-visibility-control.d.ts +18 -0
- package/dist/components/agent-visibility-control.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +326 -128
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/use-agent-chat.d.ts +10 -0
- package/dist/use-agent-chat.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { cn, Button, ThinkingOrb, Tooltip, TooltipTrigger, TooltipContent, ChatMessage, ChatMessageBubble, Markdown, AuroraText, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, ChatHeaderActions, ContextMeter, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, DataTablePaged } from '@cntyclub/ui-react';
|
|
2
|
-
import { XIcon, Trash2Icon, SquareIcon, PauseIcon, PlayIcon, CheckIcon, FileTextIcon, PaperclipIcon, MicIcon, ArrowUpIcon, CopyIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, ChevronsRightIcon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
|
|
3
|
-
import * as
|
|
1
|
+
import { cn, Button, ThinkingOrb, Tooltip, TooltipTrigger, TooltipContent, Popover, PopoverTrigger, PopoverPopup, ChatMessage, ChatMessageBubble, Markdown, AuroraText, Spinner, Checkbox, Collapsible, CollapsibleTrigger, ChatToolChip, CollapsiblePanel, ChatToolCard, ChatToolCardHeader, ChatToolCardActions, Group, Menu, MenuTrigger, MenuPopup, MenuItem, ChatHeader, ChatHeaderAvatar, ChatHeaderTitle, AvatarGroup, ChatHeaderActions, ContextMeter, Chat, ChatEmptyState, ChatEmptyStateIcon, ChatEmptyStateTitle, ChatEmptyStateDescription, ChatSuggestions, ChatSuggestion, useMediaQuery, TooltipProvider, DataTablePaged } from '@cntyclub/ui-react';
|
|
2
|
+
import { XIcon, Trash2Icon, SquareIcon, PauseIcon, PlayIcon, CheckIcon, FileTextIcon, PaperclipIcon, MicIcon, ArrowUpIcon, UsersIcon, LockIcon, GlobeIcon, CopyIcon, Maximize2Icon, ListChecksIcon, ChevronDownIcon, ShieldAlertIcon, CheckCheckIcon, UploadCloudIcon, HistoryIcon, SquarePenIcon, Minimize2Icon, ChevronsRightIcon, SparklesIcon, DownloadIcon, CodeIcon } from 'lucide-react';
|
|
3
|
+
import * as React13 from 'react';
|
|
4
4
|
import { AnimatePresence, motion } from 'motion/react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -484,7 +484,7 @@ function formatBytes(bytes) {
|
|
|
484
484
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
485
485
|
}
|
|
486
486
|
function AgentImageLightbox({ src, alt, onClose }) {
|
|
487
|
-
|
|
487
|
+
React13.useEffect(() => {
|
|
488
488
|
if (!src) return;
|
|
489
489
|
const onKey = (event) => {
|
|
490
490
|
if (event.key === "Escape") onClose();
|
|
@@ -554,24 +554,24 @@ function pickMimeType() {
|
|
|
554
554
|
return "";
|
|
555
555
|
}
|
|
556
556
|
function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError }) {
|
|
557
|
-
const [phase, setPhase] =
|
|
558
|
-
const [elapsed, setElapsed] =
|
|
559
|
-
const [playing, setPlaying] =
|
|
560
|
-
const recorderRef =
|
|
561
|
-
const streamRef =
|
|
562
|
-
const chunksRef =
|
|
563
|
-
const blobRef =
|
|
564
|
-
const audioUrlRef =
|
|
565
|
-
const audioRef =
|
|
566
|
-
const timerRef =
|
|
567
|
-
const canvasRef =
|
|
568
|
-
const audioContextRef =
|
|
569
|
-
const analyserRef =
|
|
570
|
-
const rafRef =
|
|
571
|
-
const levelsRef =
|
|
572
|
-
const onErrorRef =
|
|
557
|
+
const [phase, setPhase] = React13.useState("recording");
|
|
558
|
+
const [elapsed, setElapsed] = React13.useState(0);
|
|
559
|
+
const [playing, setPlaying] = React13.useState(false);
|
|
560
|
+
const recorderRef = React13.useRef(null);
|
|
561
|
+
const streamRef = React13.useRef(null);
|
|
562
|
+
const chunksRef = React13.useRef([]);
|
|
563
|
+
const blobRef = React13.useRef(null);
|
|
564
|
+
const audioUrlRef = React13.useRef(null);
|
|
565
|
+
const audioRef = React13.useRef(null);
|
|
566
|
+
const timerRef = React13.useRef(null);
|
|
567
|
+
const canvasRef = React13.useRef(null);
|
|
568
|
+
const audioContextRef = React13.useRef(null);
|
|
569
|
+
const analyserRef = React13.useRef(null);
|
|
570
|
+
const rafRef = React13.useRef(null);
|
|
571
|
+
const levelsRef = React13.useRef(new Array(MAX_BARS).fill(0));
|
|
572
|
+
const onErrorRef = React13.useRef(onError);
|
|
573
573
|
onErrorRef.current = onError;
|
|
574
|
-
const stopMeter =
|
|
574
|
+
const stopMeter = React13.useCallback(() => {
|
|
575
575
|
if (rafRef.current != null) {
|
|
576
576
|
cancelAnimationFrame(rafRef.current);
|
|
577
577
|
rafRef.current = null;
|
|
@@ -582,7 +582,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
|
|
|
582
582
|
if (ctx && ctx.state !== "closed") void ctx.close().catch(() => {
|
|
583
583
|
});
|
|
584
584
|
}, []);
|
|
585
|
-
const stopTracks =
|
|
585
|
+
const stopTracks = React13.useCallback(() => {
|
|
586
586
|
streamRef.current?.getTracks().forEach((track) => track.stop());
|
|
587
587
|
streamRef.current = null;
|
|
588
588
|
if (timerRef.current) {
|
|
@@ -591,7 +591,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
|
|
|
591
591
|
}
|
|
592
592
|
stopMeter();
|
|
593
593
|
}, [stopMeter]);
|
|
594
|
-
const startMeter =
|
|
594
|
+
const startMeter = React13.useCallback((stream) => {
|
|
595
595
|
const Ctor = typeof window === "undefined" ? void 0 : window.AudioContext ?? window.webkitAudioContext;
|
|
596
596
|
if (!Ctor) return;
|
|
597
597
|
let context;
|
|
@@ -661,7 +661,7 @@ function AgentVoiceRecorder({ maxSeconds, transcribe, onDone, onCancel, onError
|
|
|
661
661
|
};
|
|
662
662
|
rafRef.current = requestAnimationFrame(draw);
|
|
663
663
|
}, []);
|
|
664
|
-
|
|
664
|
+
React13.useEffect(() => {
|
|
665
665
|
let cancelled = false;
|
|
666
666
|
void (async () => {
|
|
667
667
|
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getUserMedia) {
|
|
@@ -814,40 +814,40 @@ function AgentComposer({
|
|
|
814
814
|
voiceEnabled,
|
|
815
815
|
voiceMaxSeconds = 600
|
|
816
816
|
}) {
|
|
817
|
-
const textareaRef =
|
|
818
|
-
const inputRef =
|
|
819
|
-
const [recording, setRecording] =
|
|
820
|
-
const [lightboxSrc, setLightboxSrc] =
|
|
817
|
+
const textareaRef = React13.useRef(null);
|
|
818
|
+
const inputRef = React13.useRef(null);
|
|
819
|
+
const [recording, setRecording] = React13.useState(false);
|
|
820
|
+
const [lightboxSrc, setLightboxSrc] = React13.useState(null);
|
|
821
821
|
const canSubmit = !disabled && !busy && (value.trim().length > 0 || files.length > 0);
|
|
822
822
|
const voiceAvailable = Boolean(voiceEnabled && onTranscribe);
|
|
823
|
-
const submit =
|
|
823
|
+
const submit = React13.useCallback(() => {
|
|
824
824
|
if (!canSubmit) return;
|
|
825
825
|
onSubmit(value.trim());
|
|
826
826
|
textareaRef.current?.focus();
|
|
827
827
|
}, [canSubmit, onSubmit, value]);
|
|
828
|
-
|
|
828
|
+
React13.useEffect(() => {
|
|
829
829
|
if (!disabled) textareaRef.current?.focus();
|
|
830
830
|
}, [disabled]);
|
|
831
|
-
|
|
831
|
+
React13.useEffect(() => {
|
|
832
832
|
const textarea = textareaRef.current;
|
|
833
833
|
if (!textarea) return;
|
|
834
834
|
textarea.style.height = "auto";
|
|
835
835
|
textarea.style.height = `${Math.min(textarea.scrollHeight, 144)}px`;
|
|
836
836
|
}, [value]);
|
|
837
|
-
const previews =
|
|
837
|
+
const previews = React13.useMemo(
|
|
838
838
|
() => files.map((file, originalIndex) => {
|
|
839
839
|
const image = isImageFile(file);
|
|
840
840
|
return { file, image, originalIndex, url: image ? URL.createObjectURL(file) : null };
|
|
841
841
|
}),
|
|
842
842
|
[files]
|
|
843
843
|
);
|
|
844
|
-
|
|
844
|
+
React13.useEffect(
|
|
845
845
|
() => () => {
|
|
846
846
|
previews.forEach((preview) => preview.url && URL.revokeObjectURL(preview.url));
|
|
847
847
|
},
|
|
848
848
|
[previews]
|
|
849
849
|
);
|
|
850
|
-
const ordered =
|
|
850
|
+
const ordered = React13.useMemo(
|
|
851
851
|
() => [...previews].sort((a, b) => Number(b.image) - Number(a.image)),
|
|
852
852
|
[previews]
|
|
853
853
|
);
|
|
@@ -1091,16 +1091,114 @@ function groupMessages(messages) {
|
|
|
1091
1091
|
flush();
|
|
1092
1092
|
return items;
|
|
1093
1093
|
}
|
|
1094
|
+
function audienceLabel(scope) {
|
|
1095
|
+
return scope === "event" ? "this event's organizers" : "your team";
|
|
1096
|
+
}
|
|
1097
|
+
function AgentVisibilityControl({ config, conversation, onSetVisibility }) {
|
|
1098
|
+
const [open, setOpen] = React13.useState(false);
|
|
1099
|
+
const collab = config.collaboration;
|
|
1100
|
+
const scope = collab?.scope;
|
|
1101
|
+
const isPublic = conversation.visibility === "public";
|
|
1102
|
+
if (collab?.enabled === false) return null;
|
|
1103
|
+
if (!conversation.can_toggle_visibility) {
|
|
1104
|
+
if (!isPublic) return null;
|
|
1105
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1106
|
+
/* @__PURE__ */ jsx(
|
|
1107
|
+
TooltipTrigger,
|
|
1108
|
+
{
|
|
1109
|
+
render: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-primary/10 px-2 py-0.5 text-primary text-xs", children: [
|
|
1110
|
+
/* @__PURE__ */ jsx(UsersIcon, { className: "size-3" }),
|
|
1111
|
+
"Shared"
|
|
1112
|
+
] })
|
|
1113
|
+
}
|
|
1114
|
+
),
|
|
1115
|
+
/* @__PURE__ */ jsxs(TooltipContent, { children: [
|
|
1116
|
+
"Shared with ",
|
|
1117
|
+
audienceLabel(scope)
|
|
1118
|
+
] })
|
|
1119
|
+
] });
|
|
1120
|
+
}
|
|
1121
|
+
const eventId = scope === "event" ? collab?.getEventId?.() ?? null : null;
|
|
1122
|
+
const missingEvent = scope === "event" && !eventId;
|
|
1123
|
+
const makePublic = () => {
|
|
1124
|
+
onSetVisibility("public", eventId ? { scopeEventId: eventId } : void 0);
|
|
1125
|
+
setOpen(false);
|
|
1126
|
+
};
|
|
1127
|
+
const makePrivate = () => {
|
|
1128
|
+
onSetVisibility("private");
|
|
1129
|
+
setOpen(false);
|
|
1130
|
+
};
|
|
1131
|
+
return /* @__PURE__ */ jsxs(Popover, { onOpenChange: setOpen, open, children: [
|
|
1132
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1133
|
+
/* @__PURE__ */ jsx(
|
|
1134
|
+
TooltipTrigger,
|
|
1135
|
+
{
|
|
1136
|
+
render: /* @__PURE__ */ jsx(
|
|
1137
|
+
PopoverTrigger,
|
|
1138
|
+
{
|
|
1139
|
+
render: /* @__PURE__ */ jsx(
|
|
1140
|
+
Button,
|
|
1141
|
+
{
|
|
1142
|
+
"aria-label": isPublic ? "Shared conversation" : "Private conversation",
|
|
1143
|
+
size: "icon-sm",
|
|
1144
|
+
variant: "ghost",
|
|
1145
|
+
children: isPublic ? /* @__PURE__ */ jsx(UsersIcon, { className: "text-primary" }) : /* @__PURE__ */ jsx(LockIcon, {})
|
|
1146
|
+
}
|
|
1147
|
+
)
|
|
1148
|
+
}
|
|
1149
|
+
)
|
|
1150
|
+
}
|
|
1151
|
+
),
|
|
1152
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: isPublic ? "Shared \u2014 manage access" : "Private \u2014 share" })
|
|
1153
|
+
] }),
|
|
1154
|
+
/* @__PURE__ */ jsx(PopoverPopup, { className: "w-72 p-3", children: isPublic ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1155
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-sm", children: [
|
|
1156
|
+
/* @__PURE__ */ jsx(GlobeIcon, { className: "size-4 text-primary" }),
|
|
1157
|
+
"Shared conversation"
|
|
1158
|
+
] }),
|
|
1159
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-xs", children: [
|
|
1160
|
+
"Everyone in ",
|
|
1161
|
+
audienceLabel(scope),
|
|
1162
|
+
" can see this conversation and everything in it."
|
|
1163
|
+
] }),
|
|
1164
|
+
/* @__PURE__ */ jsx(
|
|
1165
|
+
Button,
|
|
1166
|
+
{
|
|
1167
|
+
className: "mt-1 w-full",
|
|
1168
|
+
disabled: !conversation.can_go_private,
|
|
1169
|
+
onClick: makePrivate,
|
|
1170
|
+
size: "sm",
|
|
1171
|
+
variant: "outline",
|
|
1172
|
+
children: "Make private"
|
|
1173
|
+
}
|
|
1174
|
+
),
|
|
1175
|
+
!conversation.can_go_private ? /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-xs", children: "Others have already taken part, so this can no longer be made private." }) : null
|
|
1176
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1177
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 font-medium text-sm", children: [
|
|
1178
|
+
/* @__PURE__ */ jsx(UsersIcon, { className: "size-4" }),
|
|
1179
|
+
"Share this conversation"
|
|
1180
|
+
] }),
|
|
1181
|
+
/* @__PURE__ */ jsxs("p", { className: "text-muted-foreground text-xs", children: [
|
|
1182
|
+
audienceLabel(scope),
|
|
1183
|
+
" will be able to see this conversation",
|
|
1184
|
+
/* @__PURE__ */ jsx("strong", { children: " and its full history" }),
|
|
1185
|
+
", and take part in it."
|
|
1186
|
+
] }),
|
|
1187
|
+
missingEvent ? /* @__PURE__ */ jsx("p", { className: "text-destructive text-xs", children: "Open an event first \u2014 a shared conversation is tied to a specific event." }) : null,
|
|
1188
|
+
/* @__PURE__ */ jsx(Button, { className: "mt-1 w-full", disabled: missingEvent, onClick: makePublic, size: "sm", children: "Make public" })
|
|
1189
|
+
] }) })
|
|
1190
|
+
] });
|
|
1191
|
+
}
|
|
1094
1192
|
function ChatScroller({ children, className, ...props }) {
|
|
1095
|
-
const viewportRef =
|
|
1096
|
-
const pinnedRef =
|
|
1097
|
-
const handleScroll =
|
|
1193
|
+
const viewportRef = React13.useRef(null);
|
|
1194
|
+
const pinnedRef = React13.useRef(true);
|
|
1195
|
+
const handleScroll = React13.useCallback(() => {
|
|
1098
1196
|
const viewport = viewportRef.current;
|
|
1099
1197
|
if (!viewport) return;
|
|
1100
1198
|
const distanceFromBottom = viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight;
|
|
1101
1199
|
pinnedRef.current = distanceFromBottom < 64;
|
|
1102
1200
|
}, []);
|
|
1103
|
-
|
|
1201
|
+
React13.useEffect(() => {
|
|
1104
1202
|
const viewport = viewportRef.current;
|
|
1105
1203
|
if (!viewport || !pinnedRef.current) return;
|
|
1106
1204
|
viewport.scrollTop = viewport.scrollHeight;
|
|
@@ -1120,10 +1218,10 @@ function ChatScroller({ children, className, ...props }) {
|
|
|
1120
1218
|
var MIN_CHARS_PER_FRAME = 2;
|
|
1121
1219
|
var CATCH_UP = 0.22;
|
|
1122
1220
|
function usePrefersReducedMotion() {
|
|
1123
|
-
const [reduced, setReduced] =
|
|
1221
|
+
const [reduced, setReduced] = React13.useState(
|
|
1124
1222
|
() => typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
1125
1223
|
);
|
|
1126
|
-
|
|
1224
|
+
React13.useEffect(() => {
|
|
1127
1225
|
if (typeof matchMedia === "undefined") return;
|
|
1128
1226
|
const mq = matchMedia("(prefers-reduced-motion: reduce)");
|
|
1129
1227
|
const onChange = (event) => setReduced(event.matches);
|
|
@@ -1135,12 +1233,12 @@ function usePrefersReducedMotion() {
|
|
|
1135
1233
|
function useSmoothText(target, animate) {
|
|
1136
1234
|
const prefersReduced = usePrefersReducedMotion();
|
|
1137
1235
|
const enabled = animate && !prefersReduced;
|
|
1138
|
-
const [count, setCount] =
|
|
1139
|
-
const countRef =
|
|
1236
|
+
const [count, setCount] = React13.useState(() => enabled ? 0 : target.length);
|
|
1237
|
+
const countRef = React13.useRef(count);
|
|
1140
1238
|
countRef.current = count;
|
|
1141
|
-
const everEnabled =
|
|
1239
|
+
const everEnabled = React13.useRef(enabled);
|
|
1142
1240
|
if (enabled) everEnabled.current = true;
|
|
1143
|
-
|
|
1241
|
+
React13.useEffect(() => {
|
|
1144
1242
|
if (!everEnabled.current) {
|
|
1145
1243
|
if (countRef.current !== target.length) setCount(target.length);
|
|
1146
1244
|
return;
|
|
@@ -1169,14 +1267,14 @@ function useSmoothText(target, animate) {
|
|
|
1169
1267
|
return everEnabled.current ? target.slice(0, Math.floor(count)) : target;
|
|
1170
1268
|
}
|
|
1171
1269
|
function CopyButton({ className, text }) {
|
|
1172
|
-
const [copied, setCopied] =
|
|
1173
|
-
const timerRef =
|
|
1174
|
-
|
|
1270
|
+
const [copied, setCopied] = React13.useState(false);
|
|
1271
|
+
const timerRef = React13.useRef(null);
|
|
1272
|
+
React13.useEffect(() => {
|
|
1175
1273
|
return () => {
|
|
1176
1274
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1177
1275
|
};
|
|
1178
1276
|
}, []);
|
|
1179
|
-
const copy =
|
|
1277
|
+
const copy = React13.useCallback(async () => {
|
|
1180
1278
|
try {
|
|
1181
1279
|
await navigator.clipboard.writeText(text);
|
|
1182
1280
|
} catch {
|
|
@@ -1209,7 +1307,7 @@ function CopyButton({ className, text }) {
|
|
|
1209
1307
|
}
|
|
1210
1308
|
var isImageAttachment = (format) => IMAGE_ACCEPT.includes(`.${format.toLowerCase()}`);
|
|
1211
1309
|
function MessageItem({ animate = false, message }) {
|
|
1212
|
-
const [lightboxSrc, setLightboxSrc] =
|
|
1310
|
+
const [lightboxSrc, setLightboxSrc] = React13.useState(null);
|
|
1213
1311
|
const displayed = useSmoothText(message.content ?? "", animate && message.role === "assistant");
|
|
1214
1312
|
if (message.role === "user") {
|
|
1215
1313
|
const attachments = message.attachments ?? [];
|
|
@@ -1294,8 +1392,8 @@ var DEFAULT_PHRASES = [
|
|
|
1294
1392
|
];
|
|
1295
1393
|
function ThinkingIndicator({ className, intervalMs = 1800, phrases }) {
|
|
1296
1394
|
const words = phrases && phrases.length ? phrases : DEFAULT_PHRASES;
|
|
1297
|
-
const [index, setIndex] =
|
|
1298
|
-
|
|
1395
|
+
const [index, setIndex] = React13.useState(0);
|
|
1396
|
+
React13.useEffect(() => {
|
|
1299
1397
|
setIndex(0);
|
|
1300
1398
|
const timer = setInterval(() => {
|
|
1301
1399
|
setIndex((current) => (current + 1) % words.length);
|
|
@@ -1543,7 +1641,7 @@ function DownloadButton({ block, size = "sm" }) {
|
|
|
1543
1641
|
);
|
|
1544
1642
|
}
|
|
1545
1643
|
function DocumentViewer({ block, onClose }) {
|
|
1546
|
-
|
|
1644
|
+
React13.useEffect(() => {
|
|
1547
1645
|
const onKey = (event) => event.key === "Escape" && onClose();
|
|
1548
1646
|
window.addEventListener("keydown", onKey);
|
|
1549
1647
|
return () => window.removeEventListener("keydown", onKey);
|
|
@@ -1568,7 +1666,7 @@ function DocumentViewer({ block, onClose }) {
|
|
|
1568
1666
|
] });
|
|
1569
1667
|
}
|
|
1570
1668
|
function DocumentCard({ block }) {
|
|
1571
|
-
const [open, setOpen] =
|
|
1669
|
+
const [open, setOpen] = React13.useState(false);
|
|
1572
1670
|
const previewLines = (block.preview || "").split("\n").slice(0, 6).join("\n");
|
|
1573
1671
|
return /* @__PURE__ */ jsxs("div", { className: "w-full max-w-full overflow-hidden rounded-xl border border-border bg-card shadow-xs", children: [
|
|
1574
1672
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 border-border/72 border-b px-3 py-2", children: [
|
|
@@ -1690,7 +1788,7 @@ function StepDetail({
|
|
|
1690
1788
|
] });
|
|
1691
1789
|
}
|
|
1692
1790
|
function ToolActivityGroup({ describeToolCall, steps }) {
|
|
1693
|
-
const [open, setOpen] =
|
|
1791
|
+
const [open, setOpen] = React13.useState(false);
|
|
1694
1792
|
if (steps.length === 0) return null;
|
|
1695
1793
|
const last = steps[steps.length - 1];
|
|
1696
1794
|
const anyRunning = steps.some((step) => step.status === "running");
|
|
@@ -1801,12 +1899,12 @@ function AgentPanel({
|
|
|
1801
1899
|
onClose,
|
|
1802
1900
|
onToggleAgentMode
|
|
1803
1901
|
}) {
|
|
1804
|
-
const [draft, setDraft] =
|
|
1805
|
-
const [view, setView] =
|
|
1806
|
-
const [files, setFiles] =
|
|
1807
|
-
const [uploadError, setUploadError] =
|
|
1808
|
-
const [dragging, setDragging] =
|
|
1809
|
-
const dragDepth =
|
|
1902
|
+
const [draft, setDraft] = React13.useState("");
|
|
1903
|
+
const [view, setView] = React13.useState("chat");
|
|
1904
|
+
const [files, setFiles] = React13.useState([]);
|
|
1905
|
+
const [uploadError, setUploadError] = React13.useState(null);
|
|
1906
|
+
const [dragging, setDragging] = React13.useState(false);
|
|
1907
|
+
const dragDepth = React13.useRef(0);
|
|
1810
1908
|
const agentName = config.agentName ?? chat.agentInfo?.name ?? "Assistant";
|
|
1811
1909
|
const caps = {
|
|
1812
1910
|
visionEnabled: chat.agentInfo?.vision_enabled,
|
|
@@ -1817,7 +1915,25 @@ function AgentPanel({
|
|
|
1817
1915
|
"What can you help me with?",
|
|
1818
1916
|
"Give me a quick summary of my data."
|
|
1819
1917
|
];
|
|
1820
|
-
const
|
|
1918
|
+
const typingLabel = React13.useMemo(() => {
|
|
1919
|
+
const names = Object.values(chat.typingUsers);
|
|
1920
|
+
if (!names.length) return null;
|
|
1921
|
+
if (names.length === 1) return `${names[0]} is typing\u2026`;
|
|
1922
|
+
if (names.length === 2) return `${names[0]} and ${names[1]} are typing\u2026`;
|
|
1923
|
+
return `${names.length} people are typing\u2026`;
|
|
1924
|
+
}, [chat.typingUsers]);
|
|
1925
|
+
const draftEpochRef = React13.useRef(-1);
|
|
1926
|
+
React13.useEffect(() => {
|
|
1927
|
+
if (draftEpochRef.current === chat.conversationEpoch) return;
|
|
1928
|
+
draftEpochRef.current = chat.conversationEpoch;
|
|
1929
|
+
setDraft(chat.myState?.draft_text ?? "");
|
|
1930
|
+
}, [chat.conversationEpoch, chat.myState?.draft_text]);
|
|
1931
|
+
React13.useEffect(() => {
|
|
1932
|
+
if (!chat.conversationId) return;
|
|
1933
|
+
const handle = setTimeout(() => chat.saveDraft(draft), 600);
|
|
1934
|
+
return () => clearTimeout(handle);
|
|
1935
|
+
}, [draft, chat.conversationId, chat.saveDraft]);
|
|
1936
|
+
const addFiles = React13.useCallback(
|
|
1821
1937
|
(incoming) => {
|
|
1822
1938
|
const accepted = [];
|
|
1823
1939
|
let rejection = null;
|
|
@@ -1834,10 +1950,10 @@ function AgentPanel({
|
|
|
1834
1950
|
},
|
|
1835
1951
|
[config, caps.visionEnabled, caps.visionMaxMb]
|
|
1836
1952
|
);
|
|
1837
|
-
const removeFile =
|
|
1953
|
+
const removeFile = React13.useCallback((index) => {
|
|
1838
1954
|
setFiles((current) => current.filter((_, i) => i !== index));
|
|
1839
1955
|
}, []);
|
|
1840
|
-
const handleSubmit =
|
|
1956
|
+
const handleSubmit = React13.useCallback(
|
|
1841
1957
|
(text) => {
|
|
1842
1958
|
const staged = files;
|
|
1843
1959
|
setDraft("");
|
|
@@ -1847,7 +1963,7 @@ function AgentPanel({
|
|
|
1847
1963
|
},
|
|
1848
1964
|
[chat, files]
|
|
1849
1965
|
);
|
|
1850
|
-
const onDragEnter =
|
|
1966
|
+
const onDragEnter = React13.useCallback(
|
|
1851
1967
|
(event) => {
|
|
1852
1968
|
if (!uploadEnabled || !event.dataTransfer?.types?.includes("Files")) return;
|
|
1853
1969
|
dragDepth.current += 1;
|
|
@@ -1855,12 +1971,12 @@ function AgentPanel({
|
|
|
1855
1971
|
},
|
|
1856
1972
|
[uploadEnabled]
|
|
1857
1973
|
);
|
|
1858
|
-
const onDragLeave =
|
|
1974
|
+
const onDragLeave = React13.useCallback((event) => {
|
|
1859
1975
|
if (!event.dataTransfer?.types?.includes("Files")) return;
|
|
1860
1976
|
dragDepth.current = Math.max(0, dragDepth.current - 1);
|
|
1861
1977
|
if (dragDepth.current === 0) setDragging(false);
|
|
1862
1978
|
}, []);
|
|
1863
|
-
const onDrop =
|
|
1979
|
+
const onDrop = React13.useCallback(
|
|
1864
1980
|
(event) => {
|
|
1865
1981
|
if (!uploadEnabled) return;
|
|
1866
1982
|
event.preventDefault();
|
|
@@ -1871,7 +1987,7 @@ function AgentPanel({
|
|
|
1871
1987
|
},
|
|
1872
1988
|
[addFiles, uploadEnabled]
|
|
1873
1989
|
);
|
|
1874
|
-
const openHistory =
|
|
1990
|
+
const openHistory = React13.useCallback(() => {
|
|
1875
1991
|
setView("history");
|
|
1876
1992
|
void chat.refreshConversations();
|
|
1877
1993
|
}, [chat]);
|
|
@@ -1902,10 +2018,32 @@ function AgentPanel({
|
|
|
1902
2018
|
/* @__PURE__ */ jsx(ChatHeaderAvatar, {}),
|
|
1903
2019
|
/* @__PURE__ */ jsxs(ChatHeaderTitle, { children: [
|
|
1904
2020
|
/* @__PURE__ */ jsx("div", { className: "truncate font-medium text-sm", children: agentName }),
|
|
1905
|
-
config.tagline ? /* @__PURE__ */ jsx("div", { className: "truncate text-muted-foreground text-xs", children: config.tagline }) : null
|
|
1906
|
-
] })
|
|
2021
|
+
typingLabel ? /* @__PURE__ */ jsx("div", { className: "truncate text-primary text-xs", children: typingLabel }) : config.tagline ? /* @__PURE__ */ jsx("div", { className: "truncate text-muted-foreground text-xs", children: config.tagline }) : null
|
|
2022
|
+
] }),
|
|
2023
|
+
chat.participants.length > 1 ? /* @__PURE__ */ jsx(
|
|
2024
|
+
AvatarGroup,
|
|
2025
|
+
{
|
|
2026
|
+
className: "ml-0.5",
|
|
2027
|
+
items: chat.participants.map((participant) => ({
|
|
2028
|
+
alt: participant.name,
|
|
2029
|
+
name: participant.name,
|
|
2030
|
+
src: participant.avatar_url ?? void 0
|
|
2031
|
+
})),
|
|
2032
|
+
max: 4,
|
|
2033
|
+
showNameOnHover: true,
|
|
2034
|
+
size: "sm"
|
|
2035
|
+
}
|
|
2036
|
+
) : null
|
|
1907
2037
|
] }),
|
|
1908
2038
|
/* @__PURE__ */ jsxs(ChatHeaderActions, { children: [
|
|
2039
|
+
chat.currentConversation ? /* @__PURE__ */ jsx(
|
|
2040
|
+
AgentVisibilityControl,
|
|
2041
|
+
{
|
|
2042
|
+
config,
|
|
2043
|
+
conversation: chat.currentConversation,
|
|
2044
|
+
onSetVisibility: chat.setVisibility
|
|
2045
|
+
}
|
|
2046
|
+
) : null,
|
|
1909
2047
|
chat.contextMeter && chat.contextMeter.pct > 0 ? /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1910
2048
|
/* @__PURE__ */ jsx(
|
|
1911
2049
|
TooltipTrigger,
|
|
@@ -2071,7 +2209,7 @@ function AgentPanel({
|
|
|
2071
2209
|
}
|
|
2072
2210
|
}
|
|
2073
2211
|
}
|
|
2074
|
-
return grouped.map((item) => /* @__PURE__ */ jsxs(
|
|
2212
|
+
return grouped.map((item) => /* @__PURE__ */ jsxs(React13.Fragment, { children: [
|
|
2075
2213
|
item.key === anchorKey ? /* @__PURE__ */ jsx(NewMessagesDivider, {}) : null,
|
|
2076
2214
|
/* @__PURE__ */ jsx(
|
|
2077
2215
|
motion.div,
|
|
@@ -2208,25 +2346,25 @@ function buildOptimisticUserMessage(text, files) {
|
|
|
2208
2346
|
};
|
|
2209
2347
|
}
|
|
2210
2348
|
function useAgentChat(config) {
|
|
2211
|
-
const client =
|
|
2212
|
-
const configRef =
|
|
2349
|
+
const client = React13.useMemo(() => new AgentApiClient(config), [config]);
|
|
2350
|
+
const configRef = React13.useRef(config);
|
|
2213
2351
|
configRef.current = config;
|
|
2214
|
-
const [agentInfo, setAgentInfo] =
|
|
2215
|
-
const [conversationId, setConversationId] =
|
|
2216
|
-
const [conversationEpoch, setConversationEpoch] =
|
|
2217
|
-
const [conversations, setConversations] =
|
|
2218
|
-
const [messages, setMessages] =
|
|
2219
|
-
const [pendingApprovals, setPendingApprovals] =
|
|
2220
|
-
const [sending, setSending] =
|
|
2221
|
-
const [resolvingApprovalId, setResolvingApprovalId] =
|
|
2222
|
-
const [error, setError] =
|
|
2223
|
-
const [currentConversation, setCurrentConversation] =
|
|
2224
|
-
const [contextMeter, setContextMeter] =
|
|
2225
|
-
const [participants, setParticipants] =
|
|
2226
|
-
const [myState, setMyState] =
|
|
2227
|
-
const [typingUsers, setTypingUsers] =
|
|
2228
|
-
const [realtimeStatus, setRealtimeStatus] =
|
|
2229
|
-
|
|
2352
|
+
const [agentInfo, setAgentInfo] = React13.useState(null);
|
|
2353
|
+
const [conversationId, setConversationId] = React13.useState(null);
|
|
2354
|
+
const [conversationEpoch, setConversationEpoch] = React13.useState(0);
|
|
2355
|
+
const [conversations, setConversations] = React13.useState([]);
|
|
2356
|
+
const [messages, setMessages] = React13.useState([]);
|
|
2357
|
+
const [pendingApprovals, setPendingApprovals] = React13.useState([]);
|
|
2358
|
+
const [sending, setSending] = React13.useState(false);
|
|
2359
|
+
const [resolvingApprovalId, setResolvingApprovalId] = React13.useState(null);
|
|
2360
|
+
const [error, setError] = React13.useState(null);
|
|
2361
|
+
const [currentConversation, setCurrentConversation] = React13.useState(null);
|
|
2362
|
+
const [contextMeter, setContextMeter] = React13.useState(null);
|
|
2363
|
+
const [participants, setParticipants] = React13.useState([]);
|
|
2364
|
+
const [myState, setMyState] = React13.useState(null);
|
|
2365
|
+
const [typingUsers, setTypingUsers] = React13.useState({});
|
|
2366
|
+
const [realtimeStatus, setRealtimeStatus] = React13.useState("idle");
|
|
2367
|
+
React13.useEffect(() => {
|
|
2230
2368
|
let cancelled = false;
|
|
2231
2369
|
client.getConfig().then((info) => {
|
|
2232
2370
|
if (!cancelled) setAgentInfo(info);
|
|
@@ -2236,11 +2374,11 @@ function useAgentChat(config) {
|
|
|
2236
2374
|
cancelled = true;
|
|
2237
2375
|
};
|
|
2238
2376
|
}, [client]);
|
|
2239
|
-
const handleFailure =
|
|
2377
|
+
const handleFailure = React13.useCallback((err) => {
|
|
2240
2378
|
const message = err instanceof AgentApiError ? err.message : "Something went wrong. Please try again.";
|
|
2241
2379
|
setError(message);
|
|
2242
2380
|
}, []);
|
|
2243
|
-
const applyResponse =
|
|
2381
|
+
const applyResponse = React13.useCallback(
|
|
2244
2382
|
(response) => {
|
|
2245
2383
|
if (response.status === "error" && !response.messages?.length) {
|
|
2246
2384
|
setError(response.message ?? "The assistant could not answer.");
|
|
@@ -2270,7 +2408,7 @@ function useAgentChat(config) {
|
|
|
2270
2408
|
},
|
|
2271
2409
|
[]
|
|
2272
2410
|
);
|
|
2273
|
-
const handleStreamEvent =
|
|
2411
|
+
const handleStreamEvent = React13.useCallback(
|
|
2274
2412
|
(event, ctx) => {
|
|
2275
2413
|
switch (event.type) {
|
|
2276
2414
|
case "conversation":
|
|
@@ -2348,7 +2486,7 @@ function useAgentChat(config) {
|
|
|
2348
2486
|
},
|
|
2349
2487
|
[]
|
|
2350
2488
|
);
|
|
2351
|
-
const applyRealtime =
|
|
2489
|
+
const applyRealtime = React13.useCallback((event) => {
|
|
2352
2490
|
switch (event.type) {
|
|
2353
2491
|
case "sync":
|
|
2354
2492
|
setMessages((current) => mergeMessages(current, event.messages ?? []));
|
|
@@ -2388,7 +2526,7 @@ function useAgentChat(config) {
|
|
|
2388
2526
|
const realtimeEnabled = config.realtime?.enabled !== false;
|
|
2389
2527
|
const isPublic = currentConversation?.visibility === "public";
|
|
2390
2528
|
const baselineSeq = currentConversation?.last_seq ?? 0;
|
|
2391
|
-
|
|
2529
|
+
React13.useEffect(() => {
|
|
2392
2530
|
if (!realtimeEnabled || !conversationId || !isPublic) {
|
|
2393
2531
|
setRealtimeStatus("idle");
|
|
2394
2532
|
return;
|
|
@@ -2405,7 +2543,7 @@ function useAgentChat(config) {
|
|
|
2405
2543
|
};
|
|
2406
2544
|
}, [applyRealtime, baselineSeq, conversationId, isPublic, realtimeEnabled]);
|
|
2407
2545
|
const streamingEnabled = config.streaming !== false && typeof ReadableStream !== "undefined";
|
|
2408
|
-
const send =
|
|
2546
|
+
const send = React13.useCallback(
|
|
2409
2547
|
async (text, files) => {
|
|
2410
2548
|
if (sending) return;
|
|
2411
2549
|
if (!text.trim() && !(files && files.length)) return;
|
|
@@ -2444,14 +2582,14 @@ function useAgentChat(config) {
|
|
|
2444
2582
|
},
|
|
2445
2583
|
[applyResponse, client, conversationId, handleFailure, handleStreamEvent, sending, streamingEnabled]
|
|
2446
2584
|
);
|
|
2447
|
-
const transcribe =
|
|
2585
|
+
const transcribe = React13.useCallback(
|
|
2448
2586
|
async (audio) => {
|
|
2449
2587
|
const { text } = await client.transcribe(audio);
|
|
2450
2588
|
return text;
|
|
2451
2589
|
},
|
|
2452
2590
|
[client]
|
|
2453
2591
|
);
|
|
2454
|
-
const resolveApproval =
|
|
2592
|
+
const resolveApproval = React13.useCallback(
|
|
2455
2593
|
async (callId, approve) => {
|
|
2456
2594
|
if (resolvingApprovalId) return;
|
|
2457
2595
|
setResolvingApprovalId(callId);
|
|
@@ -2480,7 +2618,7 @@ function useAgentChat(config) {
|
|
|
2480
2618
|
},
|
|
2481
2619
|
[applyResponse, client, handleFailure, handleStreamEvent, resolvingApprovalId, streamingEnabled]
|
|
2482
2620
|
);
|
|
2483
|
-
const newChat =
|
|
2621
|
+
const newChat = React13.useCallback(() => {
|
|
2484
2622
|
setConversationId(null);
|
|
2485
2623
|
setMessages([]);
|
|
2486
2624
|
setPendingApprovals([]);
|
|
@@ -2492,7 +2630,7 @@ function useAgentChat(config) {
|
|
|
2492
2630
|
setTypingUsers({});
|
|
2493
2631
|
setConversationEpoch((e) => e + 1);
|
|
2494
2632
|
}, []);
|
|
2495
|
-
const refreshConversations =
|
|
2633
|
+
const refreshConversations = React13.useCallback(async () => {
|
|
2496
2634
|
try {
|
|
2497
2635
|
const { conversations: list } = await client.listConversations();
|
|
2498
2636
|
setConversations(list);
|
|
@@ -2502,7 +2640,7 @@ function useAgentChat(config) {
|
|
|
2502
2640
|
return [];
|
|
2503
2641
|
}
|
|
2504
2642
|
}, [client, handleFailure]);
|
|
2505
|
-
const openConversation =
|
|
2643
|
+
const openConversation = React13.useCallback(
|
|
2506
2644
|
async (id) => {
|
|
2507
2645
|
setError(null);
|
|
2508
2646
|
try {
|
|
@@ -2534,7 +2672,7 @@ function useAgentChat(config) {
|
|
|
2534
2672
|
},
|
|
2535
2673
|
[client, handleFailure]
|
|
2536
2674
|
);
|
|
2537
|
-
const deleteConversation =
|
|
2675
|
+
const deleteConversation = React13.useCallback(
|
|
2538
2676
|
async (id) => {
|
|
2539
2677
|
try {
|
|
2540
2678
|
await client.deleteConversation(id);
|
|
@@ -2546,7 +2684,63 @@ function useAgentChat(config) {
|
|
|
2546
2684
|
},
|
|
2547
2685
|
[client, conversationId, handleFailure, newChat]
|
|
2548
2686
|
);
|
|
2549
|
-
const
|
|
2687
|
+
const setVisibility = React13.useCallback(
|
|
2688
|
+
async (visibility, opts) => {
|
|
2689
|
+
if (!conversationId) return;
|
|
2690
|
+
setError(null);
|
|
2691
|
+
try {
|
|
2692
|
+
const scope = configRef.current.collaboration?.scope;
|
|
2693
|
+
const res = await client.setVisibility(
|
|
2694
|
+
conversationId,
|
|
2695
|
+
visibility,
|
|
2696
|
+
visibility === "public" ? { scopeType: scope, scopeEventId: opts?.scopeEventId } : void 0
|
|
2697
|
+
);
|
|
2698
|
+
if (res.status === "error") {
|
|
2699
|
+
setError(res.message ?? "Could not change the conversation's visibility.");
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2702
|
+
setCurrentConversation(
|
|
2703
|
+
(current) => current ? { ...current, visibility, can_go_private: Boolean(res.can_go_private) } : current
|
|
2704
|
+
);
|
|
2705
|
+
void client.listParticipants(conversationId).then((p) => setParticipants(p.participants ?? [])).catch(() => {
|
|
2706
|
+
});
|
|
2707
|
+
} catch (err) {
|
|
2708
|
+
handleFailure(err);
|
|
2709
|
+
}
|
|
2710
|
+
},
|
|
2711
|
+
[client, conversationId, handleFailure]
|
|
2712
|
+
);
|
|
2713
|
+
const markRead = React13.useCallback(
|
|
2714
|
+
(seq) => {
|
|
2715
|
+
if (!conversationId || seq <= 0) return;
|
|
2716
|
+
setMyState(
|
|
2717
|
+
(current) => current && seq > current.last_read_seq ? { ...current, last_read_seq: seq } : current
|
|
2718
|
+
);
|
|
2719
|
+
void client.markRead(conversationId, seq).catch(() => {
|
|
2720
|
+
});
|
|
2721
|
+
},
|
|
2722
|
+
[client, conversationId]
|
|
2723
|
+
);
|
|
2724
|
+
const saveDraft = React13.useCallback(
|
|
2725
|
+
(text) => {
|
|
2726
|
+
if (!conversationId) return;
|
|
2727
|
+
void client.saveDraft(conversationId, text).catch(() => {
|
|
2728
|
+
});
|
|
2729
|
+
},
|
|
2730
|
+
[client, conversationId]
|
|
2731
|
+
);
|
|
2732
|
+
const summarize = React13.useCallback(async () => {
|
|
2733
|
+
if (!conversationId) return;
|
|
2734
|
+
setError(null);
|
|
2735
|
+
try {
|
|
2736
|
+
await client.summarize(conversationId);
|
|
2737
|
+
const detail = await client.getConversation(conversationId);
|
|
2738
|
+
setContextMeter(detail.context_meter ?? null);
|
|
2739
|
+
} catch (err) {
|
|
2740
|
+
handleFailure(err);
|
|
2741
|
+
}
|
|
2742
|
+
}, [client, conversationId, handleFailure]);
|
|
2743
|
+
const clearError = React13.useCallback(() => setError(null), []);
|
|
2550
2744
|
return {
|
|
2551
2745
|
agentInfo,
|
|
2552
2746
|
clearError,
|
|
@@ -2557,6 +2751,7 @@ function useAgentChat(config) {
|
|
|
2557
2751
|
currentConversation,
|
|
2558
2752
|
deleteConversation,
|
|
2559
2753
|
error,
|
|
2754
|
+
markRead,
|
|
2560
2755
|
messages,
|
|
2561
2756
|
myState,
|
|
2562
2757
|
newChat,
|
|
@@ -2567,8 +2762,11 @@ function useAgentChat(config) {
|
|
|
2567
2762
|
refreshConversations,
|
|
2568
2763
|
resolveApproval,
|
|
2569
2764
|
resolvingApprovalId,
|
|
2765
|
+
saveDraft,
|
|
2570
2766
|
send,
|
|
2571
2767
|
sending,
|
|
2768
|
+
setVisibility,
|
|
2769
|
+
summarize,
|
|
2572
2770
|
transcribe,
|
|
2573
2771
|
typingUsers
|
|
2574
2772
|
};
|
|
@@ -2589,11 +2787,11 @@ function readStored(clientId) {
|
|
|
2589
2787
|
}
|
|
2590
2788
|
}
|
|
2591
2789
|
function useAlwaysApprove(clientId) {
|
|
2592
|
-
const [approved, setApproved] =
|
|
2593
|
-
|
|
2790
|
+
const [approved, setApproved] = React13.useState(() => /* @__PURE__ */ new Set());
|
|
2791
|
+
React13.useEffect(() => {
|
|
2594
2792
|
setApproved(readStored(clientId));
|
|
2595
2793
|
}, [clientId]);
|
|
2596
|
-
const persist =
|
|
2794
|
+
const persist = React13.useCallback(
|
|
2597
2795
|
(next) => {
|
|
2598
2796
|
setApproved(next);
|
|
2599
2797
|
if (typeof window === "undefined") return;
|
|
@@ -2604,8 +2802,8 @@ function useAlwaysApprove(clientId) {
|
|
|
2604
2802
|
},
|
|
2605
2803
|
[clientId]
|
|
2606
2804
|
);
|
|
2607
|
-
const isAlwaysApproved =
|
|
2608
|
-
const setAlwaysApprove =
|
|
2805
|
+
const isAlwaysApproved = React13.useCallback((toolName) => approved.has(toolName), [approved]);
|
|
2806
|
+
const setAlwaysApprove = React13.useCallback(
|
|
2609
2807
|
(toolName) => {
|
|
2610
2808
|
if (approved.has(toolName)) return;
|
|
2611
2809
|
const next = new Set(approved);
|
|
@@ -2614,7 +2812,7 @@ function useAlwaysApprove(clientId) {
|
|
|
2614
2812
|
},
|
|
2615
2813
|
[approved, persist]
|
|
2616
2814
|
);
|
|
2617
|
-
const clearAlwaysApprove =
|
|
2815
|
+
const clearAlwaysApprove = React13.useCallback(
|
|
2618
2816
|
(toolName) => {
|
|
2619
2817
|
if (!approved.has(toolName)) return;
|
|
2620
2818
|
const next = new Set(approved);
|
|
@@ -2640,10 +2838,10 @@ function AgentWidget({
|
|
|
2640
2838
|
const isControlled = controlledOpen !== void 0;
|
|
2641
2839
|
const isDocked = presentation === "docked";
|
|
2642
2840
|
const storageKey2 = `cc-agent-open:${config.clientId}`;
|
|
2643
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
2841
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React13.useState(false);
|
|
2644
2842
|
const open = controlledOpen ?? uncontrolledOpen;
|
|
2645
|
-
const [bootstrapDone, setBootstrapDone] =
|
|
2646
|
-
const persist =
|
|
2843
|
+
const [bootstrapDone, setBootstrapDone] = React13.useState(isControlled);
|
|
2844
|
+
const persist = React13.useCallback(
|
|
2647
2845
|
(next) => {
|
|
2648
2846
|
if (isControlled || !behavior.persistOpenState) return;
|
|
2649
2847
|
try {
|
|
@@ -2653,7 +2851,7 @@ function AgentWidget({
|
|
|
2653
2851
|
},
|
|
2654
2852
|
[behavior.persistOpenState, isControlled, storageKey2]
|
|
2655
2853
|
);
|
|
2656
|
-
const setOpen =
|
|
2854
|
+
const setOpen = React13.useCallback(
|
|
2657
2855
|
(next) => {
|
|
2658
2856
|
setUncontrolledOpen(next);
|
|
2659
2857
|
persist(next);
|
|
@@ -2661,14 +2859,14 @@ function AgentWidget({
|
|
|
2661
2859
|
},
|
|
2662
2860
|
[onOpenChange, persist]
|
|
2663
2861
|
);
|
|
2664
|
-
const [agentMode, setAgentMode] =
|
|
2862
|
+
const [agentMode, setAgentMode] = React13.useState(false);
|
|
2665
2863
|
const isDesktop = useMediaQuery("(min-width: 640px)", { defaultSSRValue: true, ssr: true });
|
|
2666
2864
|
const fullscreen = !isDesktop || agentMode;
|
|
2667
2865
|
const chat = useAgentChat(config);
|
|
2668
2866
|
const alwaysApprove = useAlwaysApprove(config.clientId);
|
|
2669
2867
|
const { messages, pendingApprovals, resolveApproval, resolvingApprovalId, sending } = chat;
|
|
2670
|
-
const bootRef =
|
|
2671
|
-
|
|
2868
|
+
const bootRef = React13.useRef(false);
|
|
2869
|
+
React13.useEffect(() => {
|
|
2672
2870
|
if (bootRef.current) return;
|
|
2673
2871
|
if (isControlled && !isDocked) return;
|
|
2674
2872
|
bootRef.current = true;
|
|
@@ -2700,15 +2898,15 @@ function AgentWidget({
|
|
|
2700
2898
|
cancelled = true;
|
|
2701
2899
|
};
|
|
2702
2900
|
}, []);
|
|
2703
|
-
const seenCountRef =
|
|
2704
|
-
const [baselined, setBaselined] =
|
|
2705
|
-
const [anchorId, setAnchorId] =
|
|
2706
|
-
|
|
2901
|
+
const seenCountRef = React13.useRef(0);
|
|
2902
|
+
const [baselined, setBaselined] = React13.useState(false);
|
|
2903
|
+
const [anchorId, setAnchorId] = React13.useState(null);
|
|
2904
|
+
React13.useEffect(() => {
|
|
2707
2905
|
if (baselined || !bootstrapDone) return;
|
|
2708
2906
|
seenCountRef.current = messages.length;
|
|
2709
2907
|
setBaselined(true);
|
|
2710
2908
|
}, [baselined, bootstrapDone, messages.length]);
|
|
2711
|
-
|
|
2909
|
+
React13.useEffect(() => {
|
|
2712
2910
|
if (open) {
|
|
2713
2911
|
if (messages.length > seenCountRef.current) {
|
|
2714
2912
|
const firstUnread = messages[seenCountRef.current];
|
|
@@ -2718,7 +2916,7 @@ function AgentWidget({
|
|
|
2718
2916
|
}
|
|
2719
2917
|
}, [open, messages]);
|
|
2720
2918
|
const unreadCount = open || !baselined ? 0 : messages.slice(seenCountRef.current).filter(isUnreadable).length;
|
|
2721
|
-
const workLabel =
|
|
2919
|
+
const workLabel = React13.useMemo(() => {
|
|
2722
2920
|
if (!sending) return null;
|
|
2723
2921
|
const last = messages[messages.length - 1];
|
|
2724
2922
|
if (last?.role === "tool") return "Calling tools\u2026";
|
|
@@ -2727,14 +2925,14 @@ function AgentWidget({
|
|
|
2727
2925
|
}, [sending, messages]);
|
|
2728
2926
|
const approvalWaiting = pendingApprovals.length > 0;
|
|
2729
2927
|
const { isAlwaysApproved } = alwaysApprove;
|
|
2730
|
-
|
|
2928
|
+
React13.useEffect(() => {
|
|
2731
2929
|
if (resolvingApprovalId) return;
|
|
2732
2930
|
const target = pendingApprovals.find((approval) => isAlwaysApproved(approval.tool_name));
|
|
2733
2931
|
if (target) void resolveApproval(target.id, true);
|
|
2734
2932
|
}, [pendingApprovals, resolvingApprovalId, isAlwaysApproved, resolveApproval]);
|
|
2735
|
-
const firedWriteIds =
|
|
2933
|
+
const firedWriteIds = React13.useRef(/* @__PURE__ */ new Set());
|
|
2736
2934
|
const { onWriteSuccess } = config;
|
|
2737
|
-
|
|
2935
|
+
React13.useEffect(() => {
|
|
2738
2936
|
if (!onWriteSuccess) return;
|
|
2739
2937
|
for (const message of messages) {
|
|
2740
2938
|
if (message.role !== "tool" || !message.is_write || message.tool_status !== "success") continue;
|
|
@@ -2744,9 +2942,9 @@ function AgentWidget({
|
|
|
2744
2942
|
onWriteSuccess({ arguments: args, toolName: message.tool_name ?? "" });
|
|
2745
2943
|
}
|
|
2746
2944
|
}, [messages, onWriteSuccess]);
|
|
2747
|
-
const lastNavigatedMessageId =
|
|
2748
|
-
const navEpochRef =
|
|
2749
|
-
|
|
2945
|
+
const lastNavigatedMessageId = React13.useRef(null);
|
|
2946
|
+
const navEpochRef = React13.useRef(-1);
|
|
2947
|
+
React13.useEffect(() => {
|
|
2750
2948
|
if (!open || fullscreen || !config.navigate || !config.pages?.length) return;
|
|
2751
2949
|
const toolMessages = messages.filter((message) => message.role === "tool");
|
|
2752
2950
|
const latest = toolMessages[toolMessages.length - 1];
|
|
@@ -2765,7 +2963,7 @@ function AgentWidget({
|
|
|
2765
2963
|
const scrollTo = typeof mapping.scrollTo === "function" ? mapping.scrollTo(args) : mapping.scrollTo;
|
|
2766
2964
|
config.navigate(path, { scrollTo: scrollTo ?? null });
|
|
2767
2965
|
}, [chat.conversationEpoch, config, fullscreen, messages, open]);
|
|
2768
|
-
const closePanel =
|
|
2966
|
+
const closePanel = React13.useCallback(() => {
|
|
2769
2967
|
setOpen(false);
|
|
2770
2968
|
setAgentMode(false);
|
|
2771
2969
|
}, [setOpen]);
|
|
@@ -2938,6 +3136,6 @@ function defineAgentConfig(config) {
|
|
|
2938
3136
|
return config;
|
|
2939
3137
|
}
|
|
2940
3138
|
|
|
2941
|
-
export { AgentApiClient, AgentApiError, AgentComposer, AgentImageLightbox, AgentPanel, AgentRealtimeClient, AgentVoiceRecorder, AgentWidget, ChatScroller, CopyButton, DEFAULT_ACCEPT, DocumentCard, IMAGE_ACCEPT, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, attachmentsEnabled, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, isImageFile, resolveToolPresentation, textExtensions, useAgentChat, useAlwaysApprove, useSmoothText, validateFile };
|
|
3139
|
+
export { AgentApiClient, AgentApiError, AgentComposer, AgentImageLightbox, AgentPanel, AgentRealtimeClient, AgentVisibilityControl, AgentVoiceRecorder, AgentWidget, ChatScroller, CopyButton, DEFAULT_ACCEPT, DocumentCard, IMAGE_ACCEPT, MessageItem, TaskChecklist, ThinkingIndicator, ToolActivityGroup, ToolApprovalCard, acceptAttribute, acceptedExtensions, attachmentsEnabled, defineAgentConfig, deriveDetails, fileUploadEnabled, formatBytes, groupMessages, humanizeToolName, isImageFile, resolveToolPresentation, textExtensions, useAgentChat, useAlwaysApprove, useSmoothText, validateFile };
|
|
2942
3140
|
//# sourceMappingURL=index.js.map
|
|
2943
3141
|
//# sourceMappingURL=index.js.map
|