@invergent/agent-chat-react 2.0.9 → 2.1.4
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 +2458 -1265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -15
- package/dist/index.d.ts +70 -15
- package/dist/index.js +2447 -1255
- 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, Fragment as Fragment$1, Suspense, Children } from 'react';
|
|
3
|
-
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, ChevronRightIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon,
|
|
3
|
+
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, ChevronRightIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, FolderOpenIcon, Loader2Icon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, CheckIcon, CopyIcon, TerminalIcon, SparklesIcon, ClockIcon, PlusIcon, CloudIcon, HardDriveIcon, PaperclipIcon, GlobeIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, SearchIcon, ThumbsUpIcon, ThumbsDownIcon, CircleCheckIcon, GitBranchIcon, ActivityIcon, EyeIcon, ListTodoIcon, ArrowUpIcon, ListIcon, PenLineIcon, ArrowRight, BookOpenIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1 } from 'radix-ui';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -79,87 +79,6 @@ function Button({
|
|
|
79
79
|
}
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
|
-
function BrowserControlBar({
|
|
83
|
-
sessionId,
|
|
84
|
-
hasControl,
|
|
85
|
-
adapter,
|
|
86
|
-
onControlAcquired,
|
|
87
|
-
onControlReleased
|
|
88
|
-
}) {
|
|
89
|
-
const [pending, setPending] = useState(false);
|
|
90
|
-
const [error, setError] = useState(null);
|
|
91
|
-
async function toggleControl() {
|
|
92
|
-
if (!sessionId || pending) return;
|
|
93
|
-
setPending(true);
|
|
94
|
-
setError(null);
|
|
95
|
-
try {
|
|
96
|
-
if (hasControl) {
|
|
97
|
-
await adapter.releaseBrowserControl(sessionId);
|
|
98
|
-
onControlReleased?.();
|
|
99
|
-
} else {
|
|
100
|
-
await adapter.acquireBrowserControl(sessionId);
|
|
101
|
-
onControlAcquired?.();
|
|
102
|
-
}
|
|
103
|
-
} catch (nextError) {
|
|
104
|
-
setError(nextError.message);
|
|
105
|
-
} finally {
|
|
106
|
-
setPending(false);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
110
|
-
/* @__PURE__ */ jsxs(
|
|
111
|
-
Button,
|
|
112
|
-
{
|
|
113
|
-
type: "button",
|
|
114
|
-
size: "xs",
|
|
115
|
-
variant: hasControl ? "secondary" : "default",
|
|
116
|
-
disabled: !sessionId || pending,
|
|
117
|
-
onClick: () => void toggleControl(),
|
|
118
|
-
children: [
|
|
119
|
-
hasControl ? /* @__PURE__ */ jsx(RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
120
|
-
hasControl ? "Return control" : "Take control"
|
|
121
|
-
]
|
|
122
|
-
}
|
|
123
|
-
),
|
|
124
|
-
/* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
125
|
-
/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
126
|
-
"Live"
|
|
127
|
-
] }),
|
|
128
|
-
error && /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error })
|
|
129
|
-
] });
|
|
130
|
-
}
|
|
131
|
-
function BrowserLiveView({
|
|
132
|
-
src,
|
|
133
|
-
testId = "browser-iframe"
|
|
134
|
-
}) {
|
|
135
|
-
return /* @__PURE__ */ jsx(
|
|
136
|
-
"iframe",
|
|
137
|
-
{
|
|
138
|
-
"data-testid": testId,
|
|
139
|
-
title: "Browser live view",
|
|
140
|
-
src,
|
|
141
|
-
className: "h-full w-full border-0 bg-black",
|
|
142
|
-
allow: "clipboard-read; clipboard-write"
|
|
143
|
-
}
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
function BrowserStatusDot({
|
|
147
|
-
status
|
|
148
|
-
}) {
|
|
149
|
-
return /* @__PURE__ */ jsx(
|
|
150
|
-
"span",
|
|
151
|
-
{
|
|
152
|
-
"aria-hidden": "true",
|
|
153
|
-
className: cn(
|
|
154
|
-
"inline-block size-2 shrink-0 rounded-full",
|
|
155
|
-
status === "live" && "bg-emerald-500",
|
|
156
|
-
status === "user-control" && "bg-amber-500",
|
|
157
|
-
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
158
|
-
status === "closed" && "bg-muted-foreground"
|
|
159
|
-
)
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
82
|
function Dialog({
|
|
164
83
|
...props
|
|
165
84
|
}) {
|
|
@@ -289,6 +208,194 @@ function DialogDescription({
|
|
|
289
208
|
}
|
|
290
209
|
);
|
|
291
210
|
}
|
|
211
|
+
function ConfirmDialog({
|
|
212
|
+
open,
|
|
213
|
+
title,
|
|
214
|
+
description,
|
|
215
|
+
confirmLabel = "Confirm",
|
|
216
|
+
confirmIcon,
|
|
217
|
+
variant = "destructive",
|
|
218
|
+
confirmDisabled = false,
|
|
219
|
+
onConfirm,
|
|
220
|
+
onCancel
|
|
221
|
+
}) {
|
|
222
|
+
const [loading, setLoading] = useState(false);
|
|
223
|
+
const handleConfirm = async () => {
|
|
224
|
+
setLoading(true);
|
|
225
|
+
try {
|
|
226
|
+
await onConfirm();
|
|
227
|
+
} finally {
|
|
228
|
+
setLoading(false);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
return /* @__PURE__ */ jsx(
|
|
232
|
+
Dialog,
|
|
233
|
+
{
|
|
234
|
+
open,
|
|
235
|
+
onOpenChange: (next) => {
|
|
236
|
+
if (!next && !loading) onCancel();
|
|
237
|
+
},
|
|
238
|
+
children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
239
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
240
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: title }),
|
|
241
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: description })
|
|
242
|
+
] }),
|
|
243
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
244
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", disabled: loading, onClick: onCancel, children: "Cancel" }),
|
|
245
|
+
/* @__PURE__ */ jsxs(
|
|
246
|
+
Button,
|
|
247
|
+
{
|
|
248
|
+
variant,
|
|
249
|
+
disabled: loading || confirmDisabled,
|
|
250
|
+
onClick: () => void handleConfirm(),
|
|
251
|
+
children: [
|
|
252
|
+
loading ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 size-3.5 animate-spin", "aria-hidden": "true" }) : confirmIcon,
|
|
253
|
+
confirmLabel
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
] })
|
|
258
|
+
] })
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
function BrowserControlBar({
|
|
263
|
+
sessionId,
|
|
264
|
+
hasControl,
|
|
265
|
+
adapter,
|
|
266
|
+
onControlAcquired,
|
|
267
|
+
onControlReleased,
|
|
268
|
+
onClose
|
|
269
|
+
}) {
|
|
270
|
+
const [pending, setPending] = useState(false);
|
|
271
|
+
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
272
|
+
const [error, setError] = useState(null);
|
|
273
|
+
async function toggleControl() {
|
|
274
|
+
if (!sessionId || pending) return;
|
|
275
|
+
setPending(true);
|
|
276
|
+
setError(null);
|
|
277
|
+
try {
|
|
278
|
+
if (hasControl) {
|
|
279
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
280
|
+
onControlReleased?.();
|
|
281
|
+
} else {
|
|
282
|
+
await adapter.acquireBrowserControl(sessionId);
|
|
283
|
+
onControlAcquired?.();
|
|
284
|
+
}
|
|
285
|
+
} catch (nextError) {
|
|
286
|
+
setError(nextError.message);
|
|
287
|
+
} finally {
|
|
288
|
+
setPending(false);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async function handleConfirmClose() {
|
|
292
|
+
setError(null);
|
|
293
|
+
try {
|
|
294
|
+
if (hasControl) {
|
|
295
|
+
try {
|
|
296
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
297
|
+
onControlReleased?.();
|
|
298
|
+
} catch (releaseError) {
|
|
299
|
+
console.error(
|
|
300
|
+
"Failed to release browser control before close",
|
|
301
|
+
releaseError
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (adapter.closeBrowserSession) {
|
|
306
|
+
await adapter.closeBrowserSession(sessionId);
|
|
307
|
+
}
|
|
308
|
+
setConfirmOpen(false);
|
|
309
|
+
onClose?.();
|
|
310
|
+
} catch (nextError) {
|
|
311
|
+
setError(nextError.message);
|
|
312
|
+
throw nextError;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
316
|
+
/* @__PURE__ */ jsxs(
|
|
317
|
+
Button,
|
|
318
|
+
{
|
|
319
|
+
type: "button",
|
|
320
|
+
size: "xs",
|
|
321
|
+
variant: hasControl ? "secondary" : "default",
|
|
322
|
+
disabled: !sessionId || pending,
|
|
323
|
+
onClick: () => void toggleControl(),
|
|
324
|
+
children: [
|
|
325
|
+
hasControl ? /* @__PURE__ */ jsx(RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
326
|
+
hasControl ? "Return control" : "Take control"
|
|
327
|
+
]
|
|
328
|
+
}
|
|
329
|
+
),
|
|
330
|
+
onClose && /* @__PURE__ */ jsxs(
|
|
331
|
+
Button,
|
|
332
|
+
{
|
|
333
|
+
type: "button",
|
|
334
|
+
size: "xs",
|
|
335
|
+
variant: "secondary",
|
|
336
|
+
disabled: !sessionId,
|
|
337
|
+
onClick: () => {
|
|
338
|
+
setError(null);
|
|
339
|
+
setConfirmOpen(true);
|
|
340
|
+
},
|
|
341
|
+
children: [
|
|
342
|
+
/* @__PURE__ */ jsx(XIcon, { className: "size-3", "aria-hidden": "true" }),
|
|
343
|
+
"Close"
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
),
|
|
347
|
+
/* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
348
|
+
/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
349
|
+
"Live"
|
|
350
|
+
] }),
|
|
351
|
+
error && /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error }),
|
|
352
|
+
/* @__PURE__ */ jsx(
|
|
353
|
+
ConfirmDialog,
|
|
354
|
+
{
|
|
355
|
+
open: confirmOpen,
|
|
356
|
+
title: "Close browser session?",
|
|
357
|
+
description: adapter.closeBrowserSession ? "This permanently shuts down the browser sandbox for this session. The agent will lose access to the page until it re-opens a browser. This cannot be undone." : "This hides the browser panel. The sandbox stays running so the agent can keep using it.",
|
|
358
|
+
confirmLabel: "Close browser",
|
|
359
|
+
variant: "destructive",
|
|
360
|
+
confirmIcon: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
361
|
+
onConfirm: handleConfirmClose,
|
|
362
|
+
onCancel: () => setConfirmOpen(false)
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
] });
|
|
366
|
+
}
|
|
367
|
+
function BrowserLiveView({
|
|
368
|
+
src,
|
|
369
|
+
testId = "browser-iframe"
|
|
370
|
+
}) {
|
|
371
|
+
return /* @__PURE__ */ jsx(
|
|
372
|
+
"iframe",
|
|
373
|
+
{
|
|
374
|
+
"data-testid": testId,
|
|
375
|
+
title: "Browser live view",
|
|
376
|
+
src,
|
|
377
|
+
className: "h-full w-full border-0 bg-black",
|
|
378
|
+
allow: "clipboard-read; clipboard-write"
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
function BrowserStatusDot({
|
|
383
|
+
status
|
|
384
|
+
}) {
|
|
385
|
+
return /* @__PURE__ */ jsx(
|
|
386
|
+
"span",
|
|
387
|
+
{
|
|
388
|
+
"aria-hidden": "true",
|
|
389
|
+
className: cn(
|
|
390
|
+
"inline-block size-2 shrink-0 rounded-full",
|
|
391
|
+
status === "live" && "bg-emerald-500",
|
|
392
|
+
status === "user-control" && "bg-amber-500",
|
|
393
|
+
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
394
|
+
status === "closed" && "bg-muted-foreground"
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
}
|
|
292
399
|
function TooltipProvider({
|
|
293
400
|
delayDuration = 0,
|
|
294
401
|
...props
|
|
@@ -335,7 +442,12 @@ function TooltipContent({
|
|
|
335
442
|
}
|
|
336
443
|
) });
|
|
337
444
|
}
|
|
338
|
-
function BrowserPane({
|
|
445
|
+
function BrowserPane({
|
|
446
|
+
sessionId,
|
|
447
|
+
state,
|
|
448
|
+
adapter,
|
|
449
|
+
onClose
|
|
450
|
+
}) {
|
|
339
451
|
const [fullscreenOpen, setFullscreenOpen] = useState(false);
|
|
340
452
|
const [openFullscreenOnControl, setOpenFullscreenOnControl] = useState(false);
|
|
341
453
|
const [localControlActive, setLocalControlActive] = useState(false);
|
|
@@ -395,14 +507,19 @@ function BrowserPane({ sessionId, state, adapter }) {
|
|
|
395
507
|
const handleFullscreenOpenChange = useCallback(
|
|
396
508
|
(open) => {
|
|
397
509
|
setFullscreenOpen(open);
|
|
398
|
-
if (open || !hasUserControl || !hasControlAdapter) return;
|
|
399
|
-
setLocalControlActive(false);
|
|
400
|
-
void adapter.releaseBrowserControl(sessionId).catch((error) => {
|
|
401
|
-
console.error("Failed to release browser control", error);
|
|
402
|
-
});
|
|
403
510
|
},
|
|
404
|
-
[
|
|
511
|
+
[]
|
|
405
512
|
);
|
|
513
|
+
useEffect(() => {
|
|
514
|
+
if (!canUseLiveView || !hasControlAdapter) return;
|
|
515
|
+
const handle = window.setInterval(() => {
|
|
516
|
+
void adapter.acquireBrowserControl(sessionId).catch((error) => {
|
|
517
|
+
console.error("Failed to refresh browser control", error);
|
|
518
|
+
setLocalControlActive(false);
|
|
519
|
+
});
|
|
520
|
+
}, 25e3);
|
|
521
|
+
return () => window.clearInterval(handle);
|
|
522
|
+
}, [adapter, canUseLiveView, hasControlAdapter, sessionId]);
|
|
406
523
|
useEffect(() => {
|
|
407
524
|
if (!hasLiveView || canUseLiveView) {
|
|
408
525
|
setPreviewLoading(false);
|
|
@@ -473,7 +590,8 @@ function BrowserPane({ sessionId, state, adapter }) {
|
|
|
473
590
|
setLocalControlActive(true);
|
|
474
591
|
setOpenFullscreenOnControl(true);
|
|
475
592
|
},
|
|
476
|
-
onControlReleased: () => setLocalControlActive(false)
|
|
593
|
+
onControlReleased: () => setLocalControlActive(false),
|
|
594
|
+
onClose
|
|
477
595
|
}
|
|
478
596
|
)
|
|
479
597
|
]
|
|
@@ -685,7 +803,7 @@ var ShimmerComponent = ({
|
|
|
685
803
|
return /* @__PURE__ */ jsx(
|
|
686
804
|
Component,
|
|
687
805
|
{
|
|
688
|
-
className: cn("shimmer text-
|
|
806
|
+
className: cn("shimmer text-foreground/70", className),
|
|
689
807
|
style: {
|
|
690
808
|
"--shimmer-duration": duration * 1e3,
|
|
691
809
|
"--shimmer-spread": `${dynamicSpread}px`
|
|
@@ -787,12 +905,12 @@ var ReasoningTrigger = memo(
|
|
|
787
905
|
CollapsibleTrigger,
|
|
788
906
|
{
|
|
789
907
|
className: cn(
|
|
790
|
-
"flex w-full items-center gap-2 text-
|
|
908
|
+
"flex w-full items-center gap-2 text-foreground/70 text-sm transition-colors hover:text-foreground",
|
|
791
909
|
className
|
|
792
910
|
),
|
|
793
911
|
...props,
|
|
794
912
|
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
795
|
-
/* @__PURE__ */ jsx("span", { className: "text-
|
|
913
|
+
/* @__PURE__ */ jsx("span", { className: "text-foregound/70 text-sm", children: getThinkingMessage(isStreaming, duration) }),
|
|
796
914
|
/* @__PURE__ */ jsx(
|
|
797
915
|
ChevronDownIcon,
|
|
798
916
|
{
|
|
@@ -814,7 +932,7 @@ var ReasoningContent = memo(
|
|
|
814
932
|
{
|
|
815
933
|
className: cn(
|
|
816
934
|
"mt-4 text-sm",
|
|
817
|
-
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-foreground/
|
|
935
|
+
"data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 text-foreground/70 italic outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
818
936
|
className
|
|
819
937
|
),
|
|
820
938
|
...props,
|
|
@@ -3480,7 +3598,7 @@ function buildAnswer(q, sel) {
|
|
|
3480
3598
|
if (!choice) return null;
|
|
3481
3599
|
return { question: q.prompt, answer: choice.label, is_other: false };
|
|
3482
3600
|
}
|
|
3483
|
-
function
|
|
3601
|
+
function AskUserQuestionToolBlock({ tc }) {
|
|
3484
3602
|
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
3485
3603
|
const args = useMemo(() => parseArgs(tc.args), [tc.args]);
|
|
3486
3604
|
const questions = args?.questions ?? [];
|
|
@@ -3490,7 +3608,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3490
3608
|
);
|
|
3491
3609
|
const [submitting, setSubmitting] = useState(false);
|
|
3492
3610
|
const [error, setError] = useState(null);
|
|
3493
|
-
const locked = tc.
|
|
3611
|
+
const locked = tc.askUserQuestionAnswers !== void 0 || tc.status !== "running";
|
|
3494
3612
|
useEffect(() => {
|
|
3495
3613
|
if (active >= questions.length && questions.length > 0) setActive(0);
|
|
3496
3614
|
}, [active, questions.length]);
|
|
@@ -3518,7 +3636,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3518
3636
|
setError(null);
|
|
3519
3637
|
setSubmitting(true);
|
|
3520
3638
|
try {
|
|
3521
|
-
await adapter.
|
|
3639
|
+
await adapter.submitAskUserQuestionResponse({
|
|
3522
3640
|
sessionId,
|
|
3523
3641
|
toolCallId: tc.id,
|
|
3524
3642
|
responses: answers
|
|
@@ -3551,10 +3669,10 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3551
3669
|
return () => window.removeEventListener("keydown", handler);
|
|
3552
3670
|
}, [handleCancel, handleSubmit, locked]);
|
|
3553
3671
|
if (questions.length === 0) {
|
|
3554
|
-
return /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: "
|
|
3672
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-xs text-destructive", children: "ask_user_question: no questions provided" });
|
|
3555
3673
|
}
|
|
3556
3674
|
if (locked) {
|
|
3557
|
-
return /* @__PURE__ */ jsx(
|
|
3675
|
+
return /* @__PURE__ */ jsx(AskUserQuestionLocked, { tc, questions });
|
|
3558
3676
|
}
|
|
3559
3677
|
const current = questions[active];
|
|
3560
3678
|
const currentSel = selections[active] ?? emptySelection();
|
|
@@ -3566,7 +3684,7 @@ function ClarifyToolBlock({ tc }) {
|
|
|
3566
3684
|
"max-w-2xl"
|
|
3567
3685
|
),
|
|
3568
3686
|
role: "group",
|
|
3569
|
-
"aria-label": "
|
|
3687
|
+
"aria-label": "Questions for the user",
|
|
3570
3688
|
children: [
|
|
3571
3689
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-border px-3 pt-2", children: [
|
|
3572
3690
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 overflow-x-auto text-sm", children: questions.map((_, i) => {
|
|
@@ -3730,11 +3848,11 @@ function Radio({ selected }) {
|
|
|
3730
3848
|
}
|
|
3731
3849
|
);
|
|
3732
3850
|
}
|
|
3733
|
-
function
|
|
3851
|
+
function AskUserQuestionLocked({
|
|
3734
3852
|
tc,
|
|
3735
3853
|
questions
|
|
3736
3854
|
}) {
|
|
3737
|
-
const answers = tc.
|
|
3855
|
+
const answers = tc.askUserQuestionAnswers;
|
|
3738
3856
|
const byPrompt = new Map(
|
|
3739
3857
|
answers?.map((a) => [a.question, a]) ?? []
|
|
3740
3858
|
);
|
|
@@ -4142,8 +4260,8 @@ function ToolCallBlock({
|
|
|
4142
4260
|
return /* @__PURE__ */ jsx(SkillViewBlock, { tc });
|
|
4143
4261
|
case "skill_manage":
|
|
4144
4262
|
return /* @__PURE__ */ jsx(SkillManageToolBlock, { tc });
|
|
4145
|
-
case "
|
|
4146
|
-
return /* @__PURE__ */ jsx(
|
|
4263
|
+
case "ask_user_question":
|
|
4264
|
+
return /* @__PURE__ */ jsx(AskUserQuestionToolBlock, { tc });
|
|
4147
4265
|
case "create_artifact":
|
|
4148
4266
|
return /* @__PURE__ */ jsx(ArtifactToolBlock, { tc, resolvedName: resolvedArtifactName });
|
|
4149
4267
|
case "delegate_task":
|
|
@@ -5684,7 +5802,9 @@ function ChatComposerInner({
|
|
|
5684
5802
|
showWorkspace = false,
|
|
5685
5803
|
onToggleWorkspace,
|
|
5686
5804
|
canShowBrowser = false,
|
|
5687
|
-
canShowWorkspace = false
|
|
5805
|
+
canShowWorkspace = false,
|
|
5806
|
+
viewMode = "simple",
|
|
5807
|
+
onViewModeChange
|
|
5688
5808
|
}) {
|
|
5689
5809
|
const { adapter } = useAgentChatAdapterContext();
|
|
5690
5810
|
const { textInput, attachments } = usePromptInputController();
|
|
@@ -5991,6 +6111,36 @@ function ChatComposerInner({
|
|
|
5991
6111
|
}
|
|
5992
6112
|
)
|
|
5993
6113
|
] }),
|
|
6114
|
+
onViewModeChange && /* @__PURE__ */ jsxs(
|
|
6115
|
+
"div",
|
|
6116
|
+
{
|
|
6117
|
+
role: "group",
|
|
6118
|
+
"aria-label": "Chat view mode",
|
|
6119
|
+
className: "inline-flex overflow-hidden rounded-md border border-border",
|
|
6120
|
+
children: [
|
|
6121
|
+
/* @__PURE__ */ jsx(
|
|
6122
|
+
"button",
|
|
6123
|
+
{
|
|
6124
|
+
type: "button",
|
|
6125
|
+
"aria-pressed": viewMode === "simple",
|
|
6126
|
+
onClick: () => onViewModeChange("simple"),
|
|
6127
|
+
className: viewMode === "simple" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
|
|
6128
|
+
children: "Simple"
|
|
6129
|
+
}
|
|
6130
|
+
),
|
|
6131
|
+
/* @__PURE__ */ jsx(
|
|
6132
|
+
"button",
|
|
6133
|
+
{
|
|
6134
|
+
type: "button",
|
|
6135
|
+
"aria-pressed": viewMode === "expert",
|
|
6136
|
+
onClick: () => onViewModeChange("expert"),
|
|
6137
|
+
className: viewMode === "expert" ? "bg-accent px-2 py-1 text-xs text-foreground" : "px-2 py-1 text-xs text-muted-foreground hover:text-foreground",
|
|
6138
|
+
children: "Expert"
|
|
6139
|
+
}
|
|
6140
|
+
)
|
|
6141
|
+
]
|
|
6142
|
+
}
|
|
6143
|
+
),
|
|
5994
6144
|
canShowBrowser && onToggleBrowser && /* @__PURE__ */ jsx(
|
|
5995
6145
|
PromptInputButton,
|
|
5996
6146
|
{
|
|
@@ -6157,16 +6307,26 @@ function ChatComposerInner({
|
|
|
6157
6307
|
CommandItem,
|
|
6158
6308
|
{
|
|
6159
6309
|
value: cmd.value,
|
|
6160
|
-
keywords: [cmd.description],
|
|
6310
|
+
keywords: cmd.isExpert ? [cmd.description, "expert"] : [cmd.description],
|
|
6161
6311
|
onSelect: () => handleCommandSelect(cmd.value),
|
|
6162
6312
|
className: "grid grid-cols-[12rem_1fr] items-baseline gap-3 [&_svg]:hidden",
|
|
6163
6313
|
children: [
|
|
6164
|
-
/* @__PURE__ */
|
|
6314
|
+
/* @__PURE__ */ jsxs(
|
|
6165
6315
|
"span",
|
|
6166
6316
|
{
|
|
6167
|
-
className: "
|
|
6317
|
+
className: "inline-flex items-center gap-1.5 min-w-0 max-w-full",
|
|
6168
6318
|
title: cmd.label,
|
|
6169
|
-
children:
|
|
6319
|
+
children: [
|
|
6320
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono font-semibold text-foreground truncate", children: cmd.label }),
|
|
6321
|
+
cmd.isExpert && /* @__PURE__ */ jsx(
|
|
6322
|
+
"span",
|
|
6323
|
+
{
|
|
6324
|
+
className: "shrink-0 rounded-sm bg-primary/10 px-1 text-[9px] font-semibold uppercase tracking-wider text-primary",
|
|
6325
|
+
"aria-label": "Expert specialist",
|
|
6326
|
+
children: "expert"
|
|
6327
|
+
}
|
|
6328
|
+
)
|
|
6329
|
+
]
|
|
6170
6330
|
}
|
|
6171
6331
|
),
|
|
6172
6332
|
/* @__PURE__ */ jsx(
|
|
@@ -6958,1194 +7118,1976 @@ var ErrorMessage = memo(function ErrorMessage2({
|
|
|
6958
7118
|
}
|
|
6959
7119
|
);
|
|
6960
7120
|
});
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
skill: msg.systemMeta?.skill ?? msg.content,
|
|
6968
|
-
stagedAt: msg.systemMeta?.staged_at ?? null
|
|
6969
|
-
}];
|
|
6970
|
-
}
|
|
6971
|
-
if (msg.systemKind === "artifact") {
|
|
6972
|
-
const { artifactId, name, kind, version } = unpackArtifactMeta(
|
|
6973
|
-
msg.systemMeta,
|
|
6974
|
-
msg.content
|
|
6975
|
-
);
|
|
6976
|
-
return [{
|
|
6977
|
-
kind: "artifact",
|
|
6978
|
-
key: msg.id,
|
|
6979
|
-
artifactId,
|
|
6980
|
-
name,
|
|
6981
|
-
artifactKind: kind,
|
|
6982
|
-
version
|
|
6983
|
-
}];
|
|
6984
|
-
}
|
|
6985
|
-
return [];
|
|
6986
|
-
}
|
|
6987
|
-
const entries = [];
|
|
6988
|
-
const hasToolCalls = !!(msg.toolCalls && msg.toolCalls.length > 0);
|
|
6989
|
-
const hasContent = !!(msg.content && msg.content !== msg.reasoning);
|
|
6990
|
-
const isStreaming = msg.status === "streaming" && isLast;
|
|
6991
|
-
const effectiveReasoning = hasToolCalls && hasContent ? msg.reasoning ? msg.reasoning + "\n" + msg.content : msg.content : msg.reasoning;
|
|
6992
|
-
const effectiveHasContent = hasContent && !hasToolCalls;
|
|
6993
|
-
if (effectiveReasoning) {
|
|
6994
|
-
entries.push({
|
|
6995
|
-
kind: "reasoning",
|
|
6996
|
-
key: `${msg.id}-reasoning`,
|
|
6997
|
-
reasoning: effectiveReasoning,
|
|
6998
|
-
isStreaming: isStreaming && !effectiveHasContent && !hasToolCalls
|
|
6999
|
-
});
|
|
7000
|
-
}
|
|
7001
|
-
if (hasToolCalls) {
|
|
7002
|
-
for (const tc of msg.toolCalls) {
|
|
7003
|
-
if (tc.toolName === "create_artifact") {
|
|
7004
|
-
const resolvedName = parseArgs(tc.args)?.name ?? artifactFallbacks[tc.id];
|
|
7005
|
-
const status = effectiveStatus(tc);
|
|
7006
|
-
if (!resolvedName && status !== "error") continue;
|
|
7007
|
-
entries.push({
|
|
7008
|
-
kind: "tool",
|
|
7009
|
-
key: tc.id,
|
|
7010
|
-
tc,
|
|
7011
|
-
resolvedArtifactName: resolvedName
|
|
7012
|
-
});
|
|
7013
|
-
continue;
|
|
7014
|
-
}
|
|
7015
|
-
if (tc.toolName === "terminal" && tc.status !== "running") {
|
|
7016
|
-
const parsed = parseTerminalResult(tc.result, tc.args);
|
|
7017
|
-
if (parsed && (parsed.exit_code !== 0 || parsed.error)) continue;
|
|
7018
|
-
}
|
|
7019
|
-
entries.push({ kind: "tool", key: tc.id, tc });
|
|
7020
|
-
}
|
|
7021
|
-
}
|
|
7022
|
-
if (effectiveHasContent) {
|
|
7023
|
-
entries.push({
|
|
7024
|
-
kind: "text",
|
|
7025
|
-
key: `${msg.id}-text`,
|
|
7026
|
-
content: msg.content,
|
|
7027
|
-
isStreaming,
|
|
7028
|
-
msg
|
|
7029
|
-
});
|
|
7030
|
-
}
|
|
7031
|
-
const hasRunningTool = hasToolCalls && msg.toolCalls.some(
|
|
7032
|
-
(tc) => tc.status === "running"
|
|
7033
|
-
);
|
|
7034
|
-
if (isStreaming && !effectiveHasContent && !hasRunningTool) {
|
|
7035
|
-
entries.push({ kind: "thinking", key: `${msg.id}-thinking` });
|
|
7036
|
-
}
|
|
7037
|
-
return entries;
|
|
7038
|
-
}
|
|
7039
|
-
function groupBrowserActivityEntries(entries) {
|
|
7040
|
-
const grouped = [];
|
|
7041
|
-
let buffer = [];
|
|
7042
|
-
const flush = () => {
|
|
7043
|
-
if (buffer.length === 0) return;
|
|
7044
|
-
grouped.push({
|
|
7045
|
-
kind: "browser_activity",
|
|
7046
|
-
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
7047
|
-
calls: buffer
|
|
7048
|
-
});
|
|
7049
|
-
buffer = [];
|
|
7050
|
-
};
|
|
7051
|
-
for (const entry of entries) {
|
|
7052
|
-
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
7053
|
-
buffer.push(entry.tc);
|
|
7054
|
-
continue;
|
|
7055
|
-
}
|
|
7056
|
-
flush();
|
|
7057
|
-
grouped.push(entry);
|
|
7058
|
-
}
|
|
7059
|
-
flush();
|
|
7060
|
-
return grouped;
|
|
7061
|
-
}
|
|
7062
|
-
function isBrowserToolCall(call) {
|
|
7063
|
-
return call.toolName.startsWith("browser_");
|
|
7121
|
+
|
|
7122
|
+
// src/lib/format.ts
|
|
7123
|
+
function formatFileSize(bytes) {
|
|
7124
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
7125
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
7126
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
7064
7127
|
}
|
|
7065
|
-
function
|
|
7066
|
-
const
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7128
|
+
function getLanguageHint(path) {
|
|
7129
|
+
const name = path.split("/").pop() ?? path;
|
|
7130
|
+
const dot = name.lastIndexOf(".");
|
|
7131
|
+
if (dot < 0) return "plaintext";
|
|
7132
|
+
const ext = name.slice(dot).toLowerCase();
|
|
7133
|
+
const map = {
|
|
7134
|
+
".py": "python",
|
|
7135
|
+
".js": "javascript",
|
|
7136
|
+
".ts": "typescript",
|
|
7137
|
+
".tsx": "tsx",
|
|
7138
|
+
".jsx": "jsx",
|
|
7139
|
+
".json": "json",
|
|
7140
|
+
".yaml": "yaml",
|
|
7141
|
+
".yml": "yaml",
|
|
7142
|
+
".toml": "toml",
|
|
7143
|
+
".sql": "sql",
|
|
7144
|
+
".sh": "bash",
|
|
7145
|
+
".css": "css",
|
|
7146
|
+
".html": "html",
|
|
7147
|
+
".md": "markdown",
|
|
7148
|
+
".rs": "rust",
|
|
7149
|
+
".go": "go",
|
|
7150
|
+
".java": "java",
|
|
7151
|
+
".rb": "ruby",
|
|
7152
|
+
".php": "php",
|
|
7153
|
+
".c": "c",
|
|
7154
|
+
".cpp": "cpp",
|
|
7155
|
+
".h": "c",
|
|
7156
|
+
".hpp": "cpp"
|
|
7080
7157
|
};
|
|
7081
|
-
|
|
7082
|
-
if (entry.kind === "tool" && entry.tc.toolName === "web_search") {
|
|
7083
|
-
buffer.push(entry.tc);
|
|
7084
|
-
continue;
|
|
7085
|
-
}
|
|
7086
|
-
flush();
|
|
7087
|
-
grouped.push(entry);
|
|
7088
|
-
}
|
|
7089
|
-
flush();
|
|
7090
|
-
return grouped;
|
|
7158
|
+
return map[ext] ?? "plaintext";
|
|
7091
7159
|
}
|
|
7092
|
-
function
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
}
|
|
7099
|
-
pendingSystem = [];
|
|
7100
|
-
};
|
|
7101
|
-
for (let i = 0; i < messages.length; i++) {
|
|
7102
|
-
const msg = messages[i];
|
|
7103
|
-
if (msg.role === "system") {
|
|
7104
|
-
pendingSystem.push({ msg, index: i });
|
|
7105
|
-
continue;
|
|
7106
|
-
}
|
|
7107
|
-
if (msg.role === "assistant") {
|
|
7108
|
-
const prev = groups[groups.length - 1];
|
|
7109
|
-
if (prev && prev.role === "assistant" && pendingSystem.length === 0) {
|
|
7110
|
-
prev.messages.push(msg);
|
|
7111
|
-
prev.lastGlobalIndex = i;
|
|
7112
|
-
} else {
|
|
7113
|
-
const folded = pendingSystem.map((p) => p.msg);
|
|
7114
|
-
pendingSystem = [];
|
|
7115
|
-
groups.push({
|
|
7116
|
-
role: "assistant",
|
|
7117
|
-
messages: [...folded, msg],
|
|
7118
|
-
lastGlobalIndex: i
|
|
7119
|
-
});
|
|
7120
|
-
}
|
|
7121
|
-
continue;
|
|
7160
|
+
function Skeleton({ className, ...props }) {
|
|
7161
|
+
return /* @__PURE__ */ jsx(
|
|
7162
|
+
"div",
|
|
7163
|
+
{
|
|
7164
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
7165
|
+
...props
|
|
7122
7166
|
}
|
|
7123
|
-
|
|
7124
|
-
groups.push({ role: "user", messages: [msg], lastGlobalIndex: i });
|
|
7125
|
-
}
|
|
7126
|
-
drainPendingAsOrphans();
|
|
7127
|
-
return groups;
|
|
7128
|
-
}
|
|
7129
|
-
function unpackArtifactMeta(systemMeta, fallbackName) {
|
|
7130
|
-
const meta = systemMeta ?? {};
|
|
7131
|
-
return {
|
|
7132
|
-
artifactId: meta.artifact_id ?? "",
|
|
7133
|
-
name: meta.name ?? fallbackName,
|
|
7134
|
-
kind: meta.kind ?? "markdown",
|
|
7135
|
-
version: meta.version ?? 1
|
|
7136
|
-
};
|
|
7167
|
+
);
|
|
7137
7168
|
}
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7169
|
+
var SKELETON_WIDTHS = [70, 85, 55, 90, 60, 78, 45, 82, 65, 72];
|
|
7170
|
+
var PDF_WORKER_SRC = new URL(
|
|
7171
|
+
"pdfjs-dist/legacy/build/pdf.worker.mjs",
|
|
7172
|
+
import.meta.url
|
|
7173
|
+
).toString();
|
|
7174
|
+
function FileViewer({
|
|
7175
|
+
file,
|
|
7176
|
+
loading,
|
|
7177
|
+
error,
|
|
7178
|
+
downloadUrl,
|
|
7179
|
+
onDelete,
|
|
7180
|
+
onClose
|
|
7142
7181
|
}) {
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
kind: unpacked.kind,
|
|
7162
|
-
version: unpacked.version
|
|
7163
|
-
}
|
|
7164
|
-
);
|
|
7165
|
-
}
|
|
7166
|
-
if (message.systemKind === "error" && message.errorInfo) {
|
|
7167
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
7168
|
-
}
|
|
7169
|
-
return null;
|
|
7170
|
-
}
|
|
7171
|
-
function cancelledToolLabel(toolName) {
|
|
7172
|
-
const map = {
|
|
7173
|
-
terminal: "Command",
|
|
7174
|
-
execute_code: "Execute Code",
|
|
7175
|
-
read_file: "Read",
|
|
7176
|
-
write_file: "Write",
|
|
7177
|
-
patch: "Patch",
|
|
7178
|
-
search_files: "Search Files",
|
|
7179
|
-
list_files: "List Files",
|
|
7180
|
-
web_search: "Web Search",
|
|
7181
|
-
web_extract: "Web Fetch",
|
|
7182
|
-
web_crawl: "Web Crawl",
|
|
7183
|
-
session_search: "Session Search",
|
|
7184
|
-
memory: "Memory",
|
|
7185
|
-
todo: "Todo",
|
|
7186
|
-
skills_list: "Skills",
|
|
7187
|
-
skill_view: "Skill",
|
|
7188
|
-
consult_expert: "Expert",
|
|
7189
|
-
delegate_task: "Delegate",
|
|
7190
|
-
clarify: "Clarify",
|
|
7191
|
-
process: "Process",
|
|
7192
|
-
create_artifact: "Artifact"
|
|
7193
|
-
};
|
|
7194
|
-
return map[toolName] ?? toolName;
|
|
7195
|
-
}
|
|
7196
|
-
function CancelledToolRow({ tc }) {
|
|
7197
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
7198
|
-
/* @__PURE__ */ jsx("span", { className: "font-semibold text-muted-foreground", children: cancelledToolLabel(tc.toolName) }),
|
|
7199
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70", children: "Cancelled" })
|
|
7200
|
-
] });
|
|
7201
|
-
}
|
|
7202
|
-
function TimelineEntryItem({
|
|
7203
|
-
entry,
|
|
7204
|
-
step,
|
|
7205
|
-
sessionId,
|
|
7206
|
-
onFileSelect
|
|
7207
|
-
}) {
|
|
7208
|
-
if (entry.kind === "reasoning") {
|
|
7209
|
-
return /* @__PURE__ */ jsx(ReasoningEntry, { entry, step });
|
|
7210
|
-
}
|
|
7211
|
-
if (entry.kind === "tool") {
|
|
7212
|
-
const rawStatus = effectiveStatus(entry.tc);
|
|
7213
|
-
const hideArtifactFailure = rawStatus === "error" && entry.tc.toolName === "create_artifact";
|
|
7214
|
-
const indicatorStatus = hideArtifactFailure ? "running" : rawStatus;
|
|
7215
|
-
const failureSummary = rawStatus === "error" && !hideArtifactFailure ? toolErrorSummary(entry.tc.result) : "";
|
|
7216
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7217
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7218
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7219
|
-
/* @__PURE__ */ jsx(
|
|
7220
|
-
TimelineIndicator,
|
|
7221
|
-
{
|
|
7222
|
-
className: cn("size-2 border-none", statusColorClass(indicatorStatus))
|
|
7223
|
-
}
|
|
7224
|
-
)
|
|
7225
|
-
] }),
|
|
7226
|
-
/* @__PURE__ */ jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
7227
|
-
/* @__PURE__ */ jsx(
|
|
7228
|
-
ToolCallBlock,
|
|
7229
|
-
{
|
|
7230
|
-
tc: entry.tc,
|
|
7231
|
-
resolvedArtifactName: entry.resolvedArtifactName,
|
|
7232
|
-
onFileSelect
|
|
7233
|
-
}
|
|
7234
|
-
),
|
|
7235
|
-
failureSummary ? /* @__PURE__ */ jsx("div", { className: "max-w-full truncate text-xs text-destructive", title: failureSummary, children: failureSummary }) : null
|
|
7236
|
-
] }) })
|
|
7237
|
-
] });
|
|
7238
|
-
}
|
|
7239
|
-
if (entry.kind === "browser_activity") {
|
|
7240
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7241
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7242
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7243
|
-
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
7244
|
-
] }),
|
|
7245
|
-
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
7246
|
-
] });
|
|
7247
|
-
}
|
|
7248
|
-
if (entry.kind === "web_search_group") {
|
|
7249
|
-
const allComplete = entry.calls.every((tc) => tc.status === "complete");
|
|
7250
|
-
const anyRunning = entry.calls.some((tc) => tc.status === "running");
|
|
7251
|
-
const indicatorClass = anyRunning ? "bg-emerald-500 animate-pulse" : allComplete ? "bg-emerald-500" : "bg-red-500";
|
|
7252
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7253
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7254
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7255
|
-
/* @__PURE__ */ jsx(TimelineIndicator, { className: cn("size-2 border-none", indicatorClass) })
|
|
7256
|
-
] }),
|
|
7257
|
-
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(WebSearchGroupBlock, { tcs: entry.calls }) })
|
|
7258
|
-
] });
|
|
7259
|
-
}
|
|
7260
|
-
if (entry.kind === "text") {
|
|
7261
|
-
return /* @__PURE__ */ jsx(TextEntry, { entry, step });
|
|
7262
|
-
}
|
|
7263
|
-
if (entry.kind === "skill_invoked") {
|
|
7264
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7265
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7266
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7267
|
-
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-emerald-500" })
|
|
7268
|
-
] }),
|
|
7269
|
-
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 py-1 text-sm ", children: [
|
|
7270
|
-
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
7271
|
-
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground truncate", children: entry.skill }),
|
|
7272
|
-
entry.stagedAt && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground/70 ", children: [
|
|
7273
|
-
"staged at ",
|
|
7274
|
-
entry.stagedAt
|
|
7182
|
+
const visible = loading || file !== null || error !== null;
|
|
7183
|
+
if (!visible) return null;
|
|
7184
|
+
const fileName2 = file?.path.split("/").pop() ?? "File";
|
|
7185
|
+
const lang = file ? getLanguageHint(file.path) : "";
|
|
7186
|
+
const isPdf = file?.mime_type === "application/pdf" || file?.path.toLowerCase().endsWith(".pdf") || false;
|
|
7187
|
+
const isImage = file?.encoding === "base64" && !isPdf;
|
|
7188
|
+
const HeaderIcon = isImage ? ImageIcon : FileTextIcon;
|
|
7189
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col border-t border-line", children: [
|
|
7190
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-line px-3 py-2", children: [
|
|
7191
|
+
/* @__PURE__ */ jsx(HeaderIcon, { className: "size-3.5 shrink-0 text-muted-foreground" }),
|
|
7192
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7193
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-xs font-medium", children: fileName2 }),
|
|
7194
|
+
/* @__PURE__ */ jsxs("div", { className: "truncate text-[10px] text-muted-foreground", children: [
|
|
7195
|
+
file?.path ?? "Loading...",
|
|
7196
|
+
file && /* @__PURE__ */ jsxs("span", { className: "ml-1.5", children: [
|
|
7197
|
+
formatFileSize(file.size),
|
|
7198
|
+
file.truncated && " (truncated)"
|
|
7199
|
+
] })
|
|
7275
7200
|
] })
|
|
7276
|
-
] }) })
|
|
7277
|
-
] });
|
|
7278
|
-
}
|
|
7279
|
-
if (entry.kind === "artifact") {
|
|
7280
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7281
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7282
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7283
|
-
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-sky-500" })
|
|
7284
7201
|
] }),
|
|
7285
|
-
|
|
7286
|
-
|
|
7202
|
+
downloadUrl && /* @__PURE__ */ jsx(
|
|
7203
|
+
"a",
|
|
7287
7204
|
{
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7205
|
+
href: downloadUrl,
|
|
7206
|
+
download: fileName2,
|
|
7207
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
7208
|
+
"aria-label": `Download ${fileName2}`,
|
|
7209
|
+
title: "Download",
|
|
7210
|
+
children: /* @__PURE__ */ jsx(DownloadIcon, { className: "size-3.5" })
|
|
7293
7211
|
}
|
|
7294
|
-
)
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
}
|
|
7305
|
-
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7212
|
+
),
|
|
7213
|
+
onDelete && /* @__PURE__ */ jsx(
|
|
7214
|
+
"button",
|
|
7215
|
+
{
|
|
7216
|
+
type: "button",
|
|
7217
|
+
onClick: onDelete,
|
|
7218
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
7219
|
+
"aria-label": `Delete ${fileName2}`,
|
|
7220
|
+
title: "Delete",
|
|
7221
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-3.5" })
|
|
7222
|
+
}
|
|
7223
|
+
),
|
|
7224
|
+
/* @__PURE__ */ jsx(
|
|
7225
|
+
"button",
|
|
7226
|
+
{
|
|
7227
|
+
type: "button",
|
|
7228
|
+
onClick: onClose,
|
|
7229
|
+
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
7230
|
+
"aria-label": "Close file",
|
|
7231
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
7232
|
+
}
|
|
7233
|
+
)
|
|
7314
7234
|
] }),
|
|
7315
|
-
/* @__PURE__ */
|
|
7316
|
-
/* @__PURE__ */ jsx(
|
|
7317
|
-
|
|
7318
|
-
|
|
7235
|
+
/* @__PURE__ */ jsxs(ScrollArea, { className: "min-h-0 flex-1", children: [
|
|
7236
|
+
loading && /* @__PURE__ */ jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsx(
|
|
7237
|
+
Skeleton,
|
|
7238
|
+
{
|
|
7239
|
+
className: "h-3.5 rounded",
|
|
7240
|
+
style: {
|
|
7241
|
+
width: `${SKELETON_WIDTHS[index % SKELETON_WIDTHS.length]}%`
|
|
7242
|
+
}
|
|
7243
|
+
},
|
|
7244
|
+
index
|
|
7245
|
+
)) }),
|
|
7246
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7247
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7248
|
+
/* @__PURE__ */ jsx("span", { children: error })
|
|
7249
|
+
] }),
|
|
7250
|
+
file && isPdf && file.encoding !== "base64" && /* @__PURE__ */ jsx(FileViewerError, { message: "PDF preview requires base64 file content." }),
|
|
7251
|
+
file && isPdf && file.encoding === "base64" && /* @__PURE__ */ jsx(PdfPreview, { file, fileName: fileName2 }),
|
|
7252
|
+
file && isImage && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsx(
|
|
7253
|
+
"img",
|
|
7254
|
+
{
|
|
7255
|
+
src: `data:${file.mime_type ?? "image/png"};base64,${file.content}`,
|
|
7256
|
+
alt: fileName2,
|
|
7257
|
+
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
7258
|
+
}
|
|
7259
|
+
) }),
|
|
7260
|
+
file && !isImage && !isPdf && /* @__PURE__ */ jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsx("code", { "data-language": lang, children: file.content }) })
|
|
7261
|
+
] })
|
|
7319
7262
|
] });
|
|
7320
7263
|
}
|
|
7321
|
-
function
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
})
|
|
7325
|
-
const content = useSmoothStream(entry.content, entry.isStreaming);
|
|
7326
|
-
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
7327
|
-
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
7328
|
-
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
7329
|
-
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
7330
|
-
] }),
|
|
7331
|
-
/* @__PURE__ */ jsxs(TimelineContent, { children: [
|
|
7332
|
-
/* @__PURE__ */ jsx(MessageResponse, { children: content }),
|
|
7333
|
-
entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsx(TurnFeedback, { msg: entry.msg })
|
|
7334
|
-
] })
|
|
7264
|
+
function FileViewerError({ message }) {
|
|
7265
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7266
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7267
|
+
/* @__PURE__ */ jsx("span", { children: message })
|
|
7335
7268
|
] });
|
|
7336
7269
|
}
|
|
7337
|
-
function
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
totalMessages,
|
|
7341
|
-
isRunning,
|
|
7342
|
-
sessionId,
|
|
7343
|
-
artifactFallbacks,
|
|
7344
|
-
onFileSelect,
|
|
7345
|
-
onRetry
|
|
7270
|
+
function PdfPreview({
|
|
7271
|
+
file,
|
|
7272
|
+
fileName: fileName2
|
|
7346
7273
|
}) {
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
}
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
children: [
|
|
7402
|
-
/* @__PURE__ */ jsx(AlertTriangle, { className: "size-3 shrink-0" }),
|
|
7403
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-medium", children: indicator.title }),
|
|
7404
|
-
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
|
|
7405
|
-
"attempt ",
|
|
7406
|
-
indicator.attempt
|
|
7407
|
-
] }),
|
|
7408
|
-
indicator.detail && (open ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3" }))
|
|
7409
|
-
]
|
|
7410
|
-
}
|
|
7411
|
-
),
|
|
7412
|
-
open && indicator.detail && /* @__PURE__ */ jsx("pre", { className: "mt-1 overflow-x-auto rounded-none bg-background p-2 font-mono text-[11px] whitespace-pre-wrap wrap-break-word text-muted-foreground", children: indicator.detail })
|
|
7413
|
-
]
|
|
7414
|
-
}
|
|
7415
|
-
);
|
|
7416
|
-
}
|
|
7417
|
-
function ChatThread({
|
|
7418
|
-
sessionId,
|
|
7419
|
-
messages,
|
|
7420
|
-
isRunning,
|
|
7421
|
-
isLoadingHistory = false,
|
|
7422
|
-
onSend,
|
|
7423
|
-
onStop,
|
|
7424
|
-
onFileSelect,
|
|
7425
|
-
disabled = false,
|
|
7426
|
-
disabledReason,
|
|
7427
|
-
tokenUsage,
|
|
7428
|
-
retryIndicator,
|
|
7429
|
-
onRetry,
|
|
7430
|
-
onComposerError,
|
|
7431
|
-
showBrowser = false,
|
|
7432
|
-
onToggleBrowser,
|
|
7433
|
-
showWorkspace = false,
|
|
7434
|
-
onToggleWorkspace,
|
|
7435
|
-
canShowBrowser = false,
|
|
7436
|
-
canShowWorkspace = false
|
|
7437
|
-
}) {
|
|
7438
|
-
const groups = useMemo(() => groupMessages(messages), [messages]);
|
|
7439
|
-
const artifactFallbacks = useMemo(() => {
|
|
7440
|
-
const fallbacks = {};
|
|
7441
|
-
const createArtifactToolCallIds = [];
|
|
7442
|
-
let artifactIdx = 0;
|
|
7443
|
-
for (const msg of messages) {
|
|
7444
|
-
if (msg.role === "assistant" && msg.toolCalls) {
|
|
7445
|
-
for (const tc of msg.toolCalls) {
|
|
7446
|
-
if (tc.toolName === "create_artifact" && !tc.cancelled && tc.status !== "error") {
|
|
7447
|
-
createArtifactToolCallIds.push(tc.id);
|
|
7448
|
-
}
|
|
7274
|
+
const containerRef = useRef(null);
|
|
7275
|
+
const viewerRef = useRef(null);
|
|
7276
|
+
const pdfViewerRef = useRef(null);
|
|
7277
|
+
const eventBusRef = useRef(null);
|
|
7278
|
+
const findControllerRef = useRef(null);
|
|
7279
|
+
const [error, setError] = useState(null);
|
|
7280
|
+
const [pageNumber, setPageNumber] = useState(1);
|
|
7281
|
+
const [pagesCount, setPagesCount] = useState(0);
|
|
7282
|
+
const [scale, setScale] = useState(1);
|
|
7283
|
+
const [query, setQuery] = useState("");
|
|
7284
|
+
useEffect(() => {
|
|
7285
|
+
let cancelled = false;
|
|
7286
|
+
let loadingTask = null;
|
|
7287
|
+
let pdfDocument = null;
|
|
7288
|
+
const renderPdf = async () => {
|
|
7289
|
+
setError(null);
|
|
7290
|
+
const container = containerRef.current;
|
|
7291
|
+
const viewerElement = viewerRef.current;
|
|
7292
|
+
if (!container || !viewerElement) return;
|
|
7293
|
+
const pdfBytes = decodeBase64(file.content);
|
|
7294
|
+
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
7295
|
+
pdfjs.GlobalWorkerOptions.workerSrc = PDF_WORKER_SRC;
|
|
7296
|
+
globalThis.pdfjsLib = pdfjs;
|
|
7297
|
+
const pdfViewerModule = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
7298
|
+
loadingTask = pdfjs.getDocument({ data: pdfBytes });
|
|
7299
|
+
const pdf = await loadingTask.promise;
|
|
7300
|
+
pdfDocument = pdf;
|
|
7301
|
+
if (cancelled) return;
|
|
7302
|
+
const eventBus = new pdfViewerModule.EventBus();
|
|
7303
|
+
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
7304
|
+
const findController = new pdfViewerModule.PDFFindController({
|
|
7305
|
+
eventBus,
|
|
7306
|
+
linkService
|
|
7307
|
+
});
|
|
7308
|
+
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
7309
|
+
container,
|
|
7310
|
+
viewer: viewerElement,
|
|
7311
|
+
eventBus,
|
|
7312
|
+
linkService,
|
|
7313
|
+
findController,
|
|
7314
|
+
removePageBorders: true
|
|
7315
|
+
});
|
|
7316
|
+
linkService.setViewer(pdfViewer);
|
|
7317
|
+
linkService.setDocument(pdf);
|
|
7318
|
+
findController.setDocument(pdf);
|
|
7319
|
+
const onPagesInit = () => {
|
|
7320
|
+
pdfViewer.currentScaleValue = "page-width";
|
|
7321
|
+
setScale(pdfViewer.currentScale || 1);
|
|
7322
|
+
setPagesCount(pdfViewer.pagesCount);
|
|
7323
|
+
setPageNumber(pdfViewer.currentPageNumber);
|
|
7324
|
+
};
|
|
7325
|
+
const onPageChanging = (event) => {
|
|
7326
|
+
if (typeof event.pageNumber === "number") {
|
|
7327
|
+
setPageNumber(event.pageNumber);
|
|
7449
7328
|
}
|
|
7450
|
-
}
|
|
7451
|
-
|
|
7452
|
-
if (
|
|
7453
|
-
|
|
7454
|
-
if (name) fallbacks[tcId] = name;
|
|
7329
|
+
};
|
|
7330
|
+
const onScaleChanging = (event) => {
|
|
7331
|
+
if (typeof event.scale === "number") {
|
|
7332
|
+
setScale(event.scale);
|
|
7455
7333
|
}
|
|
7456
|
-
|
|
7334
|
+
};
|
|
7335
|
+
eventBus.on("pagesinit", onPagesInit);
|
|
7336
|
+
eventBus.on("pagechanging", onPageChanging);
|
|
7337
|
+
eventBus.on("scalechanging", onScaleChanging);
|
|
7338
|
+
pdfViewerRef.current = pdfViewer;
|
|
7339
|
+
eventBusRef.current = eventBus;
|
|
7340
|
+
findControllerRef.current = findController;
|
|
7341
|
+
setPagesCount(pdf.numPages);
|
|
7342
|
+
pdfViewer.setDocument(pdf);
|
|
7343
|
+
};
|
|
7344
|
+
void renderPdf().catch((nextError) => {
|
|
7345
|
+
if (cancelled) return;
|
|
7346
|
+
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
7347
|
+
return;
|
|
7457
7348
|
}
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7349
|
+
setError(formatPdfPreviewError(nextError));
|
|
7350
|
+
});
|
|
7351
|
+
return () => {
|
|
7352
|
+
cancelled = true;
|
|
7353
|
+
loadingTask?.destroy();
|
|
7354
|
+
pdfDocument?.destroy();
|
|
7355
|
+
pdfViewerRef.current?.cleanup();
|
|
7356
|
+
pdfViewerRef.current = null;
|
|
7357
|
+
eventBusRef.current = null;
|
|
7358
|
+
findControllerRef.current = null;
|
|
7359
|
+
};
|
|
7360
|
+
}, [file.content]);
|
|
7361
|
+
const setViewerPage = (nextPage) => {
|
|
7362
|
+
const viewer = pdfViewerRef.current;
|
|
7363
|
+
if (!viewer) return;
|
|
7364
|
+
const clampedPage = Math.min(
|
|
7365
|
+
Math.max(1, nextPage),
|
|
7366
|
+
Math.max(1, viewer.pagesCount)
|
|
7367
|
+
);
|
|
7368
|
+
viewer.currentPageNumber = clampedPage;
|
|
7369
|
+
setPageNumber(clampedPage);
|
|
7370
|
+
};
|
|
7371
|
+
const setViewerScale = (nextScale) => {
|
|
7372
|
+
const viewer = pdfViewerRef.current;
|
|
7373
|
+
if (!viewer) return;
|
|
7374
|
+
const clampedScale = Math.min(3, Math.max(0.5, nextScale));
|
|
7375
|
+
viewer.currentScale = clampedScale;
|
|
7376
|
+
setScale(clampedScale);
|
|
7377
|
+
};
|
|
7378
|
+
const runFind = (findPrevious = false) => {
|
|
7379
|
+
const eventBus = eventBusRef.current;
|
|
7380
|
+
if (!eventBus || !query.trim()) return;
|
|
7381
|
+
eventBus.dispatch("find", {
|
|
7382
|
+
source: eventBus,
|
|
7383
|
+
type: "again",
|
|
7384
|
+
query,
|
|
7385
|
+
phraseSearch: true,
|
|
7386
|
+
caseSensitive: false,
|
|
7387
|
+
entireWord: false,
|
|
7388
|
+
highlightAll: true,
|
|
7389
|
+
findPrevious,
|
|
7390
|
+
matchDiacritics: true
|
|
7391
|
+
});
|
|
7392
|
+
};
|
|
7393
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-full flex-col", children: [
|
|
7394
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-1.5 border-b border-line px-2 py-1.5", children: [
|
|
7395
|
+
/* @__PURE__ */ jsx(
|
|
7396
|
+
Button,
|
|
7476
7397
|
{
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7398
|
+
type: "button",
|
|
7399
|
+
variant: "ghost",
|
|
7400
|
+
size: "icon-xs",
|
|
7401
|
+
onClick: () => setViewerPage(pageNumber - 1),
|
|
7402
|
+
disabled: pageNumber <= 1,
|
|
7403
|
+
"aria-label": "Previous PDF page",
|
|
7404
|
+
title: "Previous page",
|
|
7405
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "size-3.5" })
|
|
7480
7406
|
}
|
|
7481
|
-
)
|
|
7482
|
-
|
|
7407
|
+
),
|
|
7408
|
+
/* @__PURE__ */ jsx(
|
|
7409
|
+
Input,
|
|
7483
7410
|
{
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7411
|
+
type: "number",
|
|
7412
|
+
min: 1,
|
|
7413
|
+
max: pagesCount || 1,
|
|
7414
|
+
value: pageNumber,
|
|
7415
|
+
onChange: (event) => setViewerPage(Number(event.target.value)),
|
|
7416
|
+
"aria-label": "PDF page number",
|
|
7417
|
+
className: "h-7 w-12 border-input px-1 text-center text-xs"
|
|
7487
7418
|
}
|
|
7488
|
-
)
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
message: msg,
|
|
7496
|
-
onFileSelect
|
|
7497
|
-
},
|
|
7498
|
-
msg.id
|
|
7499
|
-
);
|
|
7500
|
-
}
|
|
7501
|
-
if (group.role === "system") {
|
|
7502
|
-
const msg = group.messages[0];
|
|
7503
|
-
const groupRetry2 = msg.id === activeFailureId ? onRetry : void 0;
|
|
7504
|
-
return /* @__PURE__ */ jsx(
|
|
7505
|
-
OrphanSystemMarker,
|
|
7506
|
-
{
|
|
7507
|
-
message: msg,
|
|
7508
|
-
sessionId,
|
|
7509
|
-
onRetry: groupRetry2
|
|
7510
|
-
},
|
|
7511
|
-
msg.id
|
|
7512
|
-
);
|
|
7513
|
-
}
|
|
7514
|
-
const groupTail = group.messages[group.messages.length - 1];
|
|
7515
|
-
const groupRetry = groupTail.id === activeFailureId ? onRetry : void 0;
|
|
7516
|
-
return /* @__PURE__ */ jsx(
|
|
7517
|
-
AssistantGroup,
|
|
7518
|
-
{
|
|
7519
|
-
messages: group.messages,
|
|
7520
|
-
lastGlobalIndex: group.lastGlobalIndex,
|
|
7521
|
-
totalMessages: messages.length,
|
|
7522
|
-
isRunning,
|
|
7523
|
-
sessionId,
|
|
7524
|
-
artifactFallbacks,
|
|
7525
|
-
onFileSelect,
|
|
7526
|
-
onRetry: groupRetry
|
|
7527
|
-
},
|
|
7528
|
-
group.messages[0].id
|
|
7529
|
-
);
|
|
7530
|
-
}),
|
|
7531
|
-
isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }) })
|
|
7532
|
-
] }) }),
|
|
7533
|
-
/* @__PURE__ */ jsx(ConversationScrollButton, {})
|
|
7534
|
-
] }),
|
|
7535
|
-
/* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
|
|
7536
|
-
retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
7537
|
-
disabled && disabledReason ? /* @__PURE__ */ jsx(
|
|
7538
|
-
"div",
|
|
7419
|
+
),
|
|
7420
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
7421
|
+
"/ ",
|
|
7422
|
+
pagesCount || "-"
|
|
7423
|
+
] }),
|
|
7424
|
+
/* @__PURE__ */ jsx(
|
|
7425
|
+
Button,
|
|
7539
7426
|
{
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7427
|
+
type: "button",
|
|
7428
|
+
variant: "ghost",
|
|
7429
|
+
size: "icon-xs",
|
|
7430
|
+
onClick: () => setViewerPage(pageNumber + 1),
|
|
7431
|
+
disabled: pagesCount > 0 && pageNumber >= pagesCount,
|
|
7432
|
+
"aria-label": "Next PDF page",
|
|
7433
|
+
title: "Next page",
|
|
7434
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3.5" })
|
|
7543
7435
|
}
|
|
7544
|
-
)
|
|
7545
|
-
|
|
7436
|
+
),
|
|
7437
|
+
/* @__PURE__ */ jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
7438
|
+
/* @__PURE__ */ jsx(
|
|
7439
|
+
Button,
|
|
7546
7440
|
{
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7441
|
+
type: "button",
|
|
7442
|
+
variant: "ghost",
|
|
7443
|
+
size: "icon-xs",
|
|
7444
|
+
onClick: () => setViewerScale(scale - 0.1),
|
|
7445
|
+
disabled: scale <= 0.5,
|
|
7446
|
+
"aria-label": "Zoom out PDF",
|
|
7447
|
+
title: "Zoom out",
|
|
7448
|
+
children: /* @__PURE__ */ jsx(MinusIcon, { className: "size-3.5" })
|
|
7449
|
+
}
|
|
7450
|
+
),
|
|
7451
|
+
/* @__PURE__ */ jsxs(
|
|
7452
|
+
"button",
|
|
7453
|
+
{
|
|
7454
|
+
type: "button",
|
|
7455
|
+
className: "h-7 min-w-12 px-1 text-xs text-muted-foreground hover:text-foreground",
|
|
7456
|
+
onClick: () => {
|
|
7457
|
+
const viewer = pdfViewerRef.current;
|
|
7458
|
+
if (!viewer) return;
|
|
7459
|
+
viewer.currentScaleValue = "page-width";
|
|
7460
|
+
setScale(viewer.currentScale || 1);
|
|
7461
|
+
},
|
|
7462
|
+
"aria-label": "Fit PDF to width",
|
|
7463
|
+
title: "Fit width",
|
|
7464
|
+
children: [
|
|
7465
|
+
Math.round(scale * 100),
|
|
7466
|
+
"%"
|
|
7467
|
+
]
|
|
7468
|
+
}
|
|
7469
|
+
),
|
|
7470
|
+
/* @__PURE__ */ jsx(
|
|
7471
|
+
Button,
|
|
7472
|
+
{
|
|
7473
|
+
type: "button",
|
|
7474
|
+
variant: "ghost",
|
|
7475
|
+
size: "icon-xs",
|
|
7476
|
+
onClick: () => setViewerScale(scale + 0.1),
|
|
7477
|
+
disabled: scale >= 3,
|
|
7478
|
+
"aria-label": "Zoom in PDF",
|
|
7479
|
+
title: "Zoom in",
|
|
7480
|
+
children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
|
|
7481
|
+
}
|
|
7482
|
+
),
|
|
7483
|
+
/* @__PURE__ */ jsx("div", { className: "mx-1 h-5 w-px bg-line" }),
|
|
7484
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "size-3.5 text-muted-foreground" }),
|
|
7485
|
+
/* @__PURE__ */ jsx(
|
|
7486
|
+
Input,
|
|
7487
|
+
{
|
|
7488
|
+
type: "search",
|
|
7489
|
+
value: query,
|
|
7490
|
+
onChange: (event) => setQuery(event.target.value),
|
|
7491
|
+
onKeyDown: (event) => {
|
|
7492
|
+
if (event.key === "Enter") runFind(event.shiftKey);
|
|
7493
|
+
},
|
|
7494
|
+
placeholder: "Find",
|
|
7495
|
+
"aria-label": "Find in PDF",
|
|
7496
|
+
className: "h-7 w-28 border-input px-1 text-xs"
|
|
7497
|
+
}
|
|
7498
|
+
),
|
|
7499
|
+
/* @__PURE__ */ jsx(
|
|
7500
|
+
Button,
|
|
7501
|
+
{
|
|
7502
|
+
type: "button",
|
|
7503
|
+
variant: "ghost",
|
|
7504
|
+
size: "xs",
|
|
7505
|
+
onClick: () => runFind(false),
|
|
7506
|
+
disabled: !query.trim(),
|
|
7507
|
+
children: "Find"
|
|
7560
7508
|
}
|
|
7561
7509
|
)
|
|
7562
|
-
] })
|
|
7510
|
+
] }),
|
|
7511
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex w-full items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7512
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7513
|
+
/* @__PURE__ */ jsx("span", { children: error })
|
|
7514
|
+
] }),
|
|
7515
|
+
!error && /* @__PURE__ */ jsx("div", { className: "relative h-[70vh] min-h-[420px] flex-1 bg-muted/20", children: /* @__PURE__ */ jsx(
|
|
7516
|
+
"div",
|
|
7517
|
+
{
|
|
7518
|
+
ref: containerRef,
|
|
7519
|
+
"aria-label": `PDF viewer for ${fileName2}`,
|
|
7520
|
+
className: "absolute inset-0 overflow-auto",
|
|
7521
|
+
children: /* @__PURE__ */ jsx("div", { ref: viewerRef, className: "pdfViewer" })
|
|
7522
|
+
}
|
|
7523
|
+
) })
|
|
7563
7524
|
] });
|
|
7564
7525
|
}
|
|
7565
|
-
|
|
7526
|
+
function decodeBase64(content) {
|
|
7527
|
+
const binary = globalThis.atob(content);
|
|
7528
|
+
const bytes = new Uint8Array(binary.length);
|
|
7529
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
7530
|
+
bytes[index] = binary.charCodeAt(index);
|
|
7531
|
+
}
|
|
7532
|
+
return bytes;
|
|
7533
|
+
}
|
|
7534
|
+
function formatPdfPreviewError(error) {
|
|
7535
|
+
if (error instanceof Error && (error.name === "InvalidCharacterError" || error.message === "Invalid character")) {
|
|
7536
|
+
return "PDF preview data is not valid base64.";
|
|
7537
|
+
}
|
|
7538
|
+
return error instanceof Error ? error.message : "Failed to render PDF preview.";
|
|
7539
|
+
}
|
|
7540
|
+
var _EXTENSION_KIND = {
|
|
7541
|
+
// Documents
|
|
7542
|
+
pdf: { icon: FileTextIcon, typeLabel: "PDF" },
|
|
7543
|
+
doc: { icon: FileTextIcon, typeLabel: "Word document" },
|
|
7544
|
+
docx: { icon: FileTextIcon, typeLabel: "Word document" },
|
|
7545
|
+
odt: { icon: FileTextIcon, typeLabel: "OpenDocument text" },
|
|
7546
|
+
rtf: { icon: FileTextIcon, typeLabel: "Rich text" },
|
|
7547
|
+
txt: { icon: FileTextIcon, typeLabel: "Text" },
|
|
7548
|
+
md: { icon: FileTextIcon, typeLabel: "Markdown" },
|
|
7549
|
+
// Spreadsheets
|
|
7550
|
+
xls: { icon: FileSpreadsheetIcon, typeLabel: "Spreadsheet" },
|
|
7551
|
+
xlsx: { icon: FileSpreadsheetIcon, typeLabel: "Spreadsheet" },
|
|
7552
|
+
ods: { icon: FileSpreadsheetIcon, typeLabel: "OpenDocument spreadsheet" },
|
|
7553
|
+
csv: { icon: FileSpreadsheetIcon, typeLabel: "CSV" },
|
|
7554
|
+
tsv: { icon: FileSpreadsheetIcon, typeLabel: "TSV" },
|
|
7555
|
+
// Presentations / charts
|
|
7556
|
+
ppt: { icon: FileChartLineIcon, typeLabel: "Presentation" },
|
|
7557
|
+
pptx: { icon: FileChartLineIcon, typeLabel: "Presentation" },
|
|
7558
|
+
// Images
|
|
7559
|
+
png: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7560
|
+
jpg: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7561
|
+
jpeg: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7562
|
+
gif: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7563
|
+
svg: { icon: FileImageIcon, typeLabel: "SVG image" },
|
|
7564
|
+
webp: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7565
|
+
bmp: { icon: FileImageIcon, typeLabel: "Image" },
|
|
7566
|
+
// Audio / video
|
|
7567
|
+
mp3: { icon: FileAudioIcon, typeLabel: "Audio" },
|
|
7568
|
+
wav: { icon: FileAudioIcon, typeLabel: "Audio" },
|
|
7569
|
+
ogg: { icon: FileAudioIcon, typeLabel: "Audio" },
|
|
7570
|
+
mp4: { icon: FileVideoIcon, typeLabel: "Video" },
|
|
7571
|
+
mov: { icon: FileVideoIcon, typeLabel: "Video" },
|
|
7572
|
+
webm: { icon: FileVideoIcon, typeLabel: "Video" },
|
|
7573
|
+
// Archives
|
|
7574
|
+
zip: { icon: FileArchiveIcon, typeLabel: "Archive" },
|
|
7575
|
+
tar: { icon: FileArchiveIcon, typeLabel: "Archive" },
|
|
7576
|
+
gz: { icon: FileArchiveIcon, typeLabel: "Archive" },
|
|
7577
|
+
bz2: { icon: FileArchiveIcon, typeLabel: "Archive" },
|
|
7578
|
+
"7z": { icon: FileArchiveIcon, typeLabel: "Archive" },
|
|
7579
|
+
// Code
|
|
7580
|
+
py: { icon: FileCodeIcon, typeLabel: "Python" },
|
|
7581
|
+
js: { icon: FileCodeIcon, typeLabel: "JavaScript" },
|
|
7582
|
+
ts: { icon: FileCodeIcon, typeLabel: "TypeScript" },
|
|
7583
|
+
tsx: { icon: FileCodeIcon, typeLabel: "TypeScript" },
|
|
7584
|
+
jsx: { icon: FileCodeIcon, typeLabel: "JavaScript" },
|
|
7585
|
+
json: { icon: FileCodeIcon, typeLabel: "JSON" },
|
|
7586
|
+
yaml: { icon: FileCodeIcon, typeLabel: "YAML" },
|
|
7587
|
+
yml: { icon: FileCodeIcon, typeLabel: "YAML" },
|
|
7588
|
+
toml: { icon: FileCodeIcon, typeLabel: "TOML" },
|
|
7589
|
+
sh: { icon: CodeIcon, typeLabel: "Shell" },
|
|
7590
|
+
rs: { icon: FileCodeIcon, typeLabel: "Rust" },
|
|
7591
|
+
go: { icon: FileCodeIcon, typeLabel: "Go" },
|
|
7592
|
+
rb: { icon: FileCodeIcon, typeLabel: "Ruby" },
|
|
7593
|
+
java: { icon: FileCodeIcon, typeLabel: "Java" },
|
|
7594
|
+
cpp: { icon: FileCodeIcon, typeLabel: "C++" },
|
|
7595
|
+
c: { icon: FileCodeIcon, typeLabel: "C" },
|
|
7596
|
+
html: { icon: FileCodeIcon, typeLabel: "HTML" },
|
|
7597
|
+
css: { icon: FileCodeIcon, typeLabel: "CSS" },
|
|
7598
|
+
scss: { icon: FileCodeIcon, typeLabel: "Sass" },
|
|
7599
|
+
sql: { icon: FileCodeIcon, typeLabel: "SQL" }
|
|
7566
7600
|
};
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
function FileTree({
|
|
7572
|
-
expanded: controlledExpanded,
|
|
7573
|
-
defaultExpanded = /* @__PURE__ */ new Set(),
|
|
7574
|
-
selectedPath,
|
|
7575
|
-
onSelect,
|
|
7576
|
-
onExpandedChange,
|
|
7577
|
-
className,
|
|
7578
|
-
children,
|
|
7579
|
-
...props
|
|
7580
|
-
}) {
|
|
7581
|
-
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
|
|
7582
|
-
const expandedPaths = controlledExpanded ?? internalExpanded;
|
|
7583
|
-
const togglePath = useCallback(
|
|
7584
|
-
(path) => {
|
|
7585
|
-
const next = new Set(expandedPaths);
|
|
7586
|
-
if (next.has(path)) {
|
|
7587
|
-
next.delete(path);
|
|
7588
|
-
} else {
|
|
7589
|
-
next.add(path);
|
|
7590
|
-
}
|
|
7591
|
-
setInternalExpanded(next);
|
|
7592
|
-
onExpandedChange?.(next);
|
|
7593
|
-
},
|
|
7594
|
-
[expandedPaths, onExpandedChange]
|
|
7595
|
-
);
|
|
7596
|
-
const contextValue = useMemo(
|
|
7597
|
-
() => ({
|
|
7598
|
-
expandedPaths,
|
|
7599
|
-
onSelect,
|
|
7600
|
-
selectedPath: selectedPath ?? void 0,
|
|
7601
|
-
togglePath
|
|
7602
|
-
}),
|
|
7603
|
-
[expandedPaths, onSelect, selectedPath, togglePath]
|
|
7604
|
-
);
|
|
7605
|
-
return /* @__PURE__ */ jsx(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
7606
|
-
"div",
|
|
7607
|
-
{
|
|
7608
|
-
className: cn("rounded-lg border bg-background text-sm", className),
|
|
7609
|
-
role: "tree",
|
|
7610
|
-
...props,
|
|
7611
|
-
children: /* @__PURE__ */ jsx("div", { className: "p-2", children })
|
|
7612
|
-
}
|
|
7613
|
-
) });
|
|
7601
|
+
function _extension(path) {
|
|
7602
|
+
const idx = path.lastIndexOf(".");
|
|
7603
|
+
if (idx < 0 || idx === path.length - 1) return "";
|
|
7604
|
+
return path.slice(idx + 1).toLowerCase();
|
|
7614
7605
|
}
|
|
7615
|
-
function
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
...props
|
|
7619
|
-
}) {
|
|
7620
|
-
return /* @__PURE__ */ jsx("span", { className: cn("shrink-0", className), ...props, children });
|
|
7606
|
+
function _fileKindFor(path) {
|
|
7607
|
+
const ext = _extension(path);
|
|
7608
|
+
return _EXTENSION_KIND[ext] ?? { icon: FileIcon, typeLabel: "File" };
|
|
7621
7609
|
}
|
|
7622
|
-
function
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
...props
|
|
7626
|
-
}) {
|
|
7627
|
-
return /* @__PURE__ */ jsx("span", { className: cn("truncate", className), ...props, children });
|
|
7610
|
+
function _basename(path) {
|
|
7611
|
+
const idx = path.lastIndexOf("/");
|
|
7612
|
+
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
7628
7613
|
}
|
|
7629
|
-
function
|
|
7614
|
+
function WorkspaceFileCard({
|
|
7615
|
+
sessionId,
|
|
7630
7616
|
path,
|
|
7631
|
-
|
|
7632
|
-
className,
|
|
7633
|
-
children,
|
|
7634
|
-
...props
|
|
7617
|
+
label
|
|
7635
7618
|
}) {
|
|
7636
|
-
const {
|
|
7637
|
-
const
|
|
7638
|
-
const
|
|
7639
|
-
const
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
const
|
|
7643
|
-
|
|
7644
|
-
}, [
|
|
7645
|
-
return /* @__PURE__ */
|
|
7619
|
+
const { adapter } = useAgentChatAdapterContext();
|
|
7620
|
+
const kind = _fileKindFor(path);
|
|
7621
|
+
const Icon = kind.icon;
|
|
7622
|
+
const downloadUrl = adapter.getWorkspaceDownloadUrl({ sessionId, path });
|
|
7623
|
+
const downloadName = _basename(path) || label;
|
|
7624
|
+
const [previewOpen, setPreviewOpen] = useState(false);
|
|
7625
|
+
const handleCardClick = useCallback(() => {
|
|
7626
|
+
setPreviewOpen(true);
|
|
7627
|
+
}, []);
|
|
7628
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7646
7629
|
/* @__PURE__ */ jsxs(
|
|
7647
7630
|
"div",
|
|
7648
7631
|
{
|
|
7632
|
+
role: "button",
|
|
7633
|
+
tabIndex: 0,
|
|
7634
|
+
onClick: handleCardClick,
|
|
7635
|
+
onKeyDown: (e) => {
|
|
7636
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7637
|
+
e.preventDefault();
|
|
7638
|
+
handleCardClick();
|
|
7639
|
+
}
|
|
7640
|
+
},
|
|
7649
7641
|
className: cn(
|
|
7650
|
-
"flex
|
|
7651
|
-
|
|
7642
|
+
"group/file flex items-center gap-3 rounded-lg border border-border",
|
|
7643
|
+
"bg-muted/20 px-3 py-2 text-left transition-colors",
|
|
7644
|
+
"cursor-pointer hover:bg-muted/40"
|
|
7652
7645
|
),
|
|
7653
7646
|
children: [
|
|
7654
|
-
/* @__PURE__ */ jsx(
|
|
7655
|
-
|
|
7656
|
-
{
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
"aria-label": isExpanded ? `Collapse ${name}` : `Expand ${name}`,
|
|
7660
|
-
children: /* @__PURE__ */ jsx(
|
|
7661
|
-
ChevronRightIcon,
|
|
7662
|
-
{
|
|
7663
|
-
className: cn(
|
|
7664
|
-
"size-4 shrink-0 text-muted-foreground transition-transform",
|
|
7665
|
-
isExpanded && "rotate-90"
|
|
7666
|
-
)
|
|
7667
|
-
}
|
|
7668
|
-
)
|
|
7669
|
-
}
|
|
7670
|
-
) }),
|
|
7647
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md border border-border bg-background", children: /* @__PURE__ */ jsx(Icon, { className: "size-5 text-muted-foreground", "aria-hidden": true }) }),
|
|
7648
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
7649
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium text-foreground", children: label }),
|
|
7650
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-xs text-muted-foreground", children: kind.typeLabel })
|
|
7651
|
+
] }),
|
|
7671
7652
|
/* @__PURE__ */ jsxs(
|
|
7672
|
-
"
|
|
7653
|
+
"a",
|
|
7673
7654
|
{
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7655
|
+
href: downloadUrl,
|
|
7656
|
+
download: downloadName,
|
|
7657
|
+
onClick: (e) => e.stopPropagation(),
|
|
7658
|
+
className: cn(
|
|
7659
|
+
"shrink-0 inline-flex items-center gap-1.5 rounded-md border border-border",
|
|
7660
|
+
"bg-background px-2.5 py-1.5 text-xs font-medium text-foreground",
|
|
7661
|
+
"transition-colors hover:bg-muted"
|
|
7662
|
+
),
|
|
7663
|
+
"aria-label": `Download ${downloadName}`,
|
|
7677
7664
|
children: [
|
|
7678
|
-
/* @__PURE__ */ jsx(
|
|
7679
|
-
|
|
7665
|
+
/* @__PURE__ */ jsx(DownloadIcon, { className: "size-3.5", "aria-hidden": true }),
|
|
7666
|
+
"Download"
|
|
7680
7667
|
]
|
|
7681
7668
|
}
|
|
7682
7669
|
)
|
|
7683
7670
|
]
|
|
7684
7671
|
}
|
|
7685
7672
|
),
|
|
7686
|
-
/* @__PURE__ */ jsx(
|
|
7687
|
-
|
|
7673
|
+
/* @__PURE__ */ jsx(
|
|
7674
|
+
WorkspaceFilePreviewDialog,
|
|
7675
|
+
{
|
|
7676
|
+
open: previewOpen,
|
|
7677
|
+
onOpenChange: setPreviewOpen,
|
|
7678
|
+
sessionId,
|
|
7679
|
+
path,
|
|
7680
|
+
downloadUrl
|
|
7681
|
+
}
|
|
7682
|
+
)
|
|
7683
|
+
] });
|
|
7688
7684
|
}
|
|
7689
|
-
function
|
|
7685
|
+
function WorkspaceFilePreviewDialog({
|
|
7686
|
+
open,
|
|
7687
|
+
onOpenChange,
|
|
7688
|
+
sessionId,
|
|
7690
7689
|
path,
|
|
7691
|
-
|
|
7692
|
-
icon,
|
|
7693
|
-
className,
|
|
7694
|
-
children,
|
|
7695
|
-
...props
|
|
7690
|
+
downloadUrl
|
|
7696
7691
|
}) {
|
|
7697
|
-
const {
|
|
7698
|
-
const
|
|
7699
|
-
const
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7692
|
+
const { adapter } = useAgentChatAdapterContext();
|
|
7693
|
+
const [file, setFile] = useState(null);
|
|
7694
|
+
const [loading, setLoading] = useState(false);
|
|
7695
|
+
const [error, setError] = useState(null);
|
|
7696
|
+
useEffect(() => {
|
|
7697
|
+
if (!open) return;
|
|
7698
|
+
let cancelled = false;
|
|
7699
|
+
setLoading(true);
|
|
7700
|
+
setError(null);
|
|
7701
|
+
setFile(null);
|
|
7702
|
+
adapter.getWorkspaceFile({ sessionId, path }).then((result) => {
|
|
7703
|
+
if (cancelled) return;
|
|
7704
|
+
setFile(result);
|
|
7705
|
+
setLoading(false);
|
|
7706
|
+
}).catch((err) => {
|
|
7707
|
+
if (cancelled) return;
|
|
7708
|
+
const message = err instanceof Error ? err.message : "Failed to load file";
|
|
7709
|
+
setError(message);
|
|
7710
|
+
setLoading(false);
|
|
7711
|
+
});
|
|
7712
|
+
return () => {
|
|
7713
|
+
cancelled = true;
|
|
7714
|
+
};
|
|
7715
|
+
}, [adapter, sessionId, path, open]);
|
|
7716
|
+
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "flex h-[80vh] w-full max-w-5xl flex-col gap-0 overflow-hidden p-0", children: [
|
|
7717
|
+
/* @__PURE__ */ jsx(DialogHeader, { className: "border-b border-line px-4 py-3", children: /* @__PURE__ */ jsx(DialogTitle, { className: "truncate text-sm", children: _basename(path) }) }),
|
|
7718
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx(
|
|
7719
|
+
FileViewer,
|
|
7720
|
+
{
|
|
7721
|
+
file,
|
|
7722
|
+
loading,
|
|
7723
|
+
error,
|
|
7724
|
+
downloadUrl,
|
|
7725
|
+
onDelete: null,
|
|
7726
|
+
onClose: () => onOpenChange(false)
|
|
7706
7727
|
}
|
|
7707
|
-
}
|
|
7708
|
-
|
|
7709
|
-
);
|
|
7710
|
-
return /* @__PURE__ */ jsx(
|
|
7711
|
-
"div",
|
|
7712
|
-
{
|
|
7713
|
-
className: cn(
|
|
7714
|
-
"group flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
|
|
7715
|
-
isSelected && "bg-muted",
|
|
7716
|
-
className
|
|
7717
|
-
),
|
|
7718
|
-
onClick: handleClick,
|
|
7719
|
-
onKeyDown: handleKeyDown,
|
|
7720
|
-
role: "treeitem",
|
|
7721
|
-
tabIndex: 0,
|
|
7722
|
-
...props,
|
|
7723
|
-
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7724
|
-
/* @__PURE__ */ jsx("span", { className: "size-4 shrink-0" }),
|
|
7725
|
-
/* @__PURE__ */ jsx(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsx(FileIcon, { className: "size-4 text-muted-foreground" }) }),
|
|
7726
|
-
/* @__PURE__ */ jsx(FileTreeName, { children: name })
|
|
7727
|
-
] })
|
|
7728
|
-
}
|
|
7729
|
-
);
|
|
7730
|
-
}
|
|
7731
|
-
function Skeleton({ className, ...props }) {
|
|
7732
|
-
return /* @__PURE__ */ jsx(
|
|
7733
|
-
"div",
|
|
7734
|
-
{
|
|
7735
|
-
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
7736
|
-
...props
|
|
7737
|
-
}
|
|
7738
|
-
);
|
|
7739
|
-
}
|
|
7740
|
-
|
|
7741
|
-
// src/lib/format.ts
|
|
7742
|
-
function formatFileSize(bytes) {
|
|
7743
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
7744
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
7745
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
7728
|
+
) })
|
|
7729
|
+
] }) });
|
|
7746
7730
|
}
|
|
7747
|
-
function
|
|
7748
|
-
const
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
".
|
|
7754
|
-
".
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
".json": "json",
|
|
7759
|
-
".yaml": "yaml",
|
|
7760
|
-
".yml": "yaml",
|
|
7761
|
-
".toml": "toml",
|
|
7762
|
-
".sql": "sql",
|
|
7763
|
-
".sh": "bash",
|
|
7764
|
-
".css": "css",
|
|
7765
|
-
".html": "html",
|
|
7766
|
-
".md": "markdown",
|
|
7767
|
-
".rs": "rust",
|
|
7768
|
-
".go": "go",
|
|
7769
|
-
".java": "java",
|
|
7770
|
-
".rb": "ruby",
|
|
7771
|
-
".php": "php",
|
|
7772
|
-
".c": "c",
|
|
7773
|
-
".cpp": "cpp",
|
|
7774
|
-
".h": "c",
|
|
7775
|
-
".hpp": "cpp"
|
|
7776
|
-
};
|
|
7777
|
-
return map[ext] ?? "plaintext";
|
|
7731
|
+
function resolveArtifactRef(ref, messages) {
|
|
7732
|
+
for (const msg of messages) {
|
|
7733
|
+
if (msg.role !== "system" || msg.systemKind !== "artifact") continue;
|
|
7734
|
+
const meta = msg.systemMeta ?? {};
|
|
7735
|
+
if (meta.artifact_id !== ref) continue;
|
|
7736
|
+
const kind = meta.kind ?? "markdown";
|
|
7737
|
+
const version = typeof meta.version === "number" ? meta.version : 1;
|
|
7738
|
+
const name = typeof meta.name === "string" ? meta.name : "";
|
|
7739
|
+
return { artifactId: ref, name, kind, version };
|
|
7740
|
+
}
|
|
7741
|
+
return null;
|
|
7778
7742
|
}
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
file,
|
|
7786
|
-
loading,
|
|
7787
|
-
error,
|
|
7788
|
-
downloadUrl,
|
|
7789
|
-
onDelete,
|
|
7790
|
-
onClose
|
|
7743
|
+
function TurnSummaryCard({
|
|
7744
|
+
summary,
|
|
7745
|
+
sessionId,
|
|
7746
|
+
messages,
|
|
7747
|
+
onFileSelect,
|
|
7748
|
+
onCommandSelect
|
|
7791
7749
|
}) {
|
|
7792
|
-
const
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
"button",
|
|
7825
|
-
{
|
|
7826
|
-
type: "button",
|
|
7827
|
-
onClick: onDelete,
|
|
7828
|
-
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive",
|
|
7829
|
-
"aria-label": `Delete ${fileName2}`,
|
|
7830
|
-
title: "Delete",
|
|
7831
|
-
children: /* @__PURE__ */ jsx(TrashIcon, { className: "size-3.5" })
|
|
7832
|
-
}
|
|
7833
|
-
),
|
|
7834
|
-
/* @__PURE__ */ jsx(
|
|
7835
|
-
"button",
|
|
7836
|
-
{
|
|
7837
|
-
type: "button",
|
|
7838
|
-
onClick: onClose,
|
|
7839
|
-
className: "shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
7840
|
-
"aria-label": "Close file",
|
|
7841
|
-
children: /* @__PURE__ */ jsx(XIcon, { className: "size-3.5" })
|
|
7750
|
+
const hasRecap = summary.recap.trim().length > 0;
|
|
7751
|
+
const hasArtifacts = summary.artifacts.length > 0;
|
|
7752
|
+
if (!hasRecap && !hasArtifacts) return null;
|
|
7753
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded border border-border bg-muted/20 px-3 py-2 text-sm", children: [
|
|
7754
|
+
hasRecap && /* @__PURE__ */ jsx("p", { className: "mb-2 whitespace-pre-wrap text-foreground", children: summary.recap }),
|
|
7755
|
+
hasArtifacts && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: summary.artifacts.map((artifact, i) => {
|
|
7756
|
+
const key = `${artifact.kind}:${artifact.ref}:${i}`;
|
|
7757
|
+
if (artifact.kind === "file" && sessionId) {
|
|
7758
|
+
return /* @__PURE__ */ jsx(
|
|
7759
|
+
WorkspaceFileCard,
|
|
7760
|
+
{
|
|
7761
|
+
sessionId,
|
|
7762
|
+
path: artifact.ref,
|
|
7763
|
+
label: artifact.label
|
|
7764
|
+
},
|
|
7765
|
+
key
|
|
7766
|
+
);
|
|
7767
|
+
}
|
|
7768
|
+
if (artifact.kind === "artifact") {
|
|
7769
|
+
const resolved = sessionId ? resolveArtifactRef(artifact.ref, messages) : null;
|
|
7770
|
+
if (resolved && sessionId) {
|
|
7771
|
+
return /* @__PURE__ */ jsx(
|
|
7772
|
+
ArtifactBlock,
|
|
7773
|
+
{
|
|
7774
|
+
sessionId,
|
|
7775
|
+
artifactId: resolved.artifactId,
|
|
7776
|
+
name: resolved.name || artifact.label,
|
|
7777
|
+
kind: resolved.kind,
|
|
7778
|
+
version: resolved.version
|
|
7779
|
+
},
|
|
7780
|
+
key
|
|
7781
|
+
);
|
|
7842
7782
|
}
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
loading && /* @__PURE__ */ jsx("div", { className: "space-y-1.5 p-3", children: Array.from({ length: 10 }).map((_, index) => /* @__PURE__ */ jsx(
|
|
7847
|
-
Skeleton,
|
|
7783
|
+
}
|
|
7784
|
+
return /* @__PURE__ */ jsxs(
|
|
7785
|
+
"div",
|
|
7848
7786
|
{
|
|
7849
|
-
className: "
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7787
|
+
className: "flex items-baseline gap-2 text-sm",
|
|
7788
|
+
children: [
|
|
7789
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", "aria-hidden": true, children: "\u2022" }),
|
|
7790
|
+
/* @__PURE__ */ jsx(
|
|
7791
|
+
ArtifactRow,
|
|
7792
|
+
{
|
|
7793
|
+
artifact,
|
|
7794
|
+
sessionId,
|
|
7795
|
+
messages,
|
|
7796
|
+
onFileSelect,
|
|
7797
|
+
onCommandSelect
|
|
7798
|
+
}
|
|
7799
|
+
)
|
|
7800
|
+
]
|
|
7853
7801
|
},
|
|
7854
|
-
|
|
7855
|
-
)
|
|
7856
|
-
|
|
7857
|
-
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7858
|
-
/* @__PURE__ */ jsx("span", { children: error })
|
|
7859
|
-
] }),
|
|
7860
|
-
file && isPdf && file.encoding !== "base64" && /* @__PURE__ */ jsx(FileViewerError, { message: "PDF preview requires base64 file content." }),
|
|
7861
|
-
file && isPdf && file.encoding === "base64" && /* @__PURE__ */ jsx(PdfPreview, { file, fileName: fileName2 }),
|
|
7862
|
-
file && isImage && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsx(
|
|
7863
|
-
"img",
|
|
7864
|
-
{
|
|
7865
|
-
src: `data:${file.mime_type ?? "image/png"};base64,${file.content}`,
|
|
7866
|
-
alt: fileName2,
|
|
7867
|
-
className: "max-h-[60vh] max-w-full rounded object-contain"
|
|
7868
|
-
}
|
|
7869
|
-
) }),
|
|
7870
|
-
file && !isImage && !isPdf && /* @__PURE__ */ jsx("pre", { className: "wrap-break-word whitespace-pre-wrap p-3 text-[11px] leading-relaxed text-foreground", children: /* @__PURE__ */ jsx("code", { "data-language": lang, children: file.content }) })
|
|
7871
|
-
] })
|
|
7872
|
-
] });
|
|
7873
|
-
}
|
|
7874
|
-
function FileViewerError({ message }) {
|
|
7875
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 text-xs text-destructive", children: [
|
|
7876
|
-
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-3.5 shrink-0" }),
|
|
7877
|
-
/* @__PURE__ */ jsx("span", { children: message })
|
|
7802
|
+
key
|
|
7803
|
+
);
|
|
7804
|
+
}) })
|
|
7878
7805
|
] });
|
|
7879
7806
|
}
|
|
7880
|
-
function
|
|
7881
|
-
|
|
7882
|
-
|
|
7807
|
+
function ArtifactRow({
|
|
7808
|
+
artifact,
|
|
7809
|
+
sessionId,
|
|
7810
|
+
messages,
|
|
7811
|
+
onFileSelect,
|
|
7812
|
+
onCommandSelect
|
|
7883
7813
|
}) {
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
let cancelled = false;
|
|
7896
|
-
let loadingTask = null;
|
|
7897
|
-
let pdfDocument = null;
|
|
7898
|
-
const renderPdf = async () => {
|
|
7899
|
-
setError(null);
|
|
7900
|
-
const container = containerRef.current;
|
|
7901
|
-
const viewerElement = viewerRef.current;
|
|
7902
|
-
if (!container || !viewerElement) return;
|
|
7903
|
-
const pdfBytes = decodeBase64(file.content);
|
|
7904
|
-
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
7905
|
-
pdfjs.GlobalWorkerOptions.workerSrc = PDF_WORKER_SRC;
|
|
7906
|
-
globalThis.pdfjsLib = pdfjs;
|
|
7907
|
-
const pdfViewerModule = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
7908
|
-
loadingTask = pdfjs.getDocument({ data: pdfBytes });
|
|
7909
|
-
const pdf = await loadingTask.promise;
|
|
7910
|
-
pdfDocument = pdf;
|
|
7911
|
-
if (cancelled) return;
|
|
7912
|
-
const eventBus = new pdfViewerModule.EventBus();
|
|
7913
|
-
const linkService = new pdfViewerModule.PDFLinkService({ eventBus });
|
|
7914
|
-
const findController = new pdfViewerModule.PDFFindController({
|
|
7915
|
-
eventBus,
|
|
7916
|
-
linkService
|
|
7917
|
-
});
|
|
7918
|
-
const pdfViewer = new pdfViewerModule.PDFViewer({
|
|
7919
|
-
container,
|
|
7920
|
-
viewer: viewerElement,
|
|
7921
|
-
eventBus,
|
|
7922
|
-
linkService,
|
|
7923
|
-
findController,
|
|
7924
|
-
removePageBorders: true
|
|
7925
|
-
});
|
|
7926
|
-
linkService.setViewer(pdfViewer);
|
|
7927
|
-
linkService.setDocument(pdf);
|
|
7928
|
-
findController.setDocument(pdf);
|
|
7929
|
-
const onPagesInit = () => {
|
|
7930
|
-
pdfViewer.currentScaleValue = "page-width";
|
|
7931
|
-
setScale(pdfViewer.currentScale || 1);
|
|
7932
|
-
setPagesCount(pdfViewer.pagesCount);
|
|
7933
|
-
setPageNumber(pdfViewer.currentPageNumber);
|
|
7934
|
-
};
|
|
7935
|
-
const onPageChanging = (event) => {
|
|
7936
|
-
if (typeof event.pageNumber === "number") {
|
|
7937
|
-
setPageNumber(event.pageNumber);
|
|
7938
|
-
}
|
|
7939
|
-
};
|
|
7940
|
-
const onScaleChanging = (event) => {
|
|
7941
|
-
if (typeof event.scale === "number") {
|
|
7942
|
-
setScale(event.scale);
|
|
7943
|
-
}
|
|
7944
|
-
};
|
|
7945
|
-
eventBus.on("pagesinit", onPagesInit);
|
|
7946
|
-
eventBus.on("pagechanging", onPageChanging);
|
|
7947
|
-
eventBus.on("scalechanging", onScaleChanging);
|
|
7948
|
-
pdfViewerRef.current = pdfViewer;
|
|
7949
|
-
eventBusRef.current = eventBus;
|
|
7950
|
-
findControllerRef.current = findController;
|
|
7951
|
-
setPagesCount(pdf.numPages);
|
|
7952
|
-
pdfViewer.setDocument(pdf);
|
|
7953
|
-
};
|
|
7954
|
-
void renderPdf().catch((nextError) => {
|
|
7955
|
-
if (cancelled) return;
|
|
7956
|
-
if (nextError instanceof Error && nextError.name === "RenderingCancelledException") {
|
|
7957
|
-
return;
|
|
7814
|
+
if (artifact.kind === "file") {
|
|
7815
|
+
if (!onFileSelect) {
|
|
7816
|
+
return /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
7817
|
+
}
|
|
7818
|
+
return /* @__PURE__ */ jsx(
|
|
7819
|
+
"button",
|
|
7820
|
+
{
|
|
7821
|
+
type: "button",
|
|
7822
|
+
onClick: () => onFileSelect(artifact.ref),
|
|
7823
|
+
className: "truncate cursor-pointer text-primary hover:underline",
|
|
7824
|
+
children: artifact.label
|
|
7958
7825
|
}
|
|
7959
|
-
setError(formatPdfPreviewError(nextError));
|
|
7960
|
-
});
|
|
7961
|
-
return () => {
|
|
7962
|
-
cancelled = true;
|
|
7963
|
-
loadingTask?.destroy();
|
|
7964
|
-
pdfDocument?.destroy();
|
|
7965
|
-
pdfViewerRef.current?.cleanup();
|
|
7966
|
-
pdfViewerRef.current = null;
|
|
7967
|
-
eventBusRef.current = null;
|
|
7968
|
-
findControllerRef.current = null;
|
|
7969
|
-
};
|
|
7970
|
-
}, [file.content]);
|
|
7971
|
-
const setViewerPage = (nextPage) => {
|
|
7972
|
-
const viewer = pdfViewerRef.current;
|
|
7973
|
-
if (!viewer) return;
|
|
7974
|
-
const clampedPage = Math.min(
|
|
7975
|
-
Math.max(1, nextPage),
|
|
7976
|
-
Math.max(1, viewer.pagesCount)
|
|
7977
7826
|
);
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
|
|
7991
|
-
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
|
|
8000
|
-
|
|
7827
|
+
}
|
|
7828
|
+
if (artifact.kind === "url") {
|
|
7829
|
+
return /* @__PURE__ */ jsx(
|
|
7830
|
+
"a",
|
|
7831
|
+
{
|
|
7832
|
+
href: artifact.ref,
|
|
7833
|
+
target: "_blank",
|
|
7834
|
+
rel: "noopener noreferrer",
|
|
7835
|
+
className: "truncate text-primary hover:underline",
|
|
7836
|
+
children: artifact.label
|
|
7837
|
+
}
|
|
7838
|
+
);
|
|
7839
|
+
}
|
|
7840
|
+
if (artifact.kind === "command") {
|
|
7841
|
+
if (!onCommandSelect) {
|
|
7842
|
+
return /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
7843
|
+
}
|
|
7844
|
+
return /* @__PURE__ */ jsx(
|
|
7845
|
+
"button",
|
|
7846
|
+
{
|
|
7847
|
+
type: "button",
|
|
7848
|
+
onClick: () => onCommandSelect(artifact.ref),
|
|
7849
|
+
className: "truncate text-left cursor-pointer text-primary hover:underline",
|
|
7850
|
+
children: artifact.label
|
|
7851
|
+
}
|
|
7852
|
+
);
|
|
7853
|
+
}
|
|
7854
|
+
const resolved = sessionId ? resolveArtifactRef(artifact.ref, messages) : null;
|
|
7855
|
+
if (!resolved) {
|
|
7856
|
+
return /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
7857
|
+
}
|
|
7858
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
|
|
7859
|
+
ArtifactBlock,
|
|
7860
|
+
{
|
|
7861
|
+
sessionId,
|
|
7862
|
+
artifactId: resolved.artifactId,
|
|
7863
|
+
name: resolved.name || artifact.label,
|
|
7864
|
+
kind: resolved.kind,
|
|
7865
|
+
version: resolved.version
|
|
7866
|
+
}
|
|
7867
|
+
) });
|
|
7868
|
+
}
|
|
7869
|
+
function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
7870
|
+
if (msg.role === "system") {
|
|
7871
|
+
if (msg.systemKind === "skill_invoked") {
|
|
7872
|
+
return [{
|
|
7873
|
+
kind: "skill_invoked",
|
|
7874
|
+
key: msg.id,
|
|
7875
|
+
skill: msg.systemMeta?.skill ?? msg.content,
|
|
7876
|
+
stagedAt: msg.systemMeta?.staged_at ?? null
|
|
7877
|
+
}];
|
|
7878
|
+
}
|
|
7879
|
+
if (msg.systemKind === "artifact") {
|
|
7880
|
+
const { artifactId, name, kind, version } = unpackArtifactMeta(
|
|
7881
|
+
msg.systemMeta,
|
|
7882
|
+
msg.content
|
|
7883
|
+
);
|
|
7884
|
+
return [{
|
|
7885
|
+
kind: "artifact",
|
|
7886
|
+
key: msg.id,
|
|
7887
|
+
artifactId,
|
|
7888
|
+
name,
|
|
7889
|
+
artifactKind: kind,
|
|
7890
|
+
version
|
|
7891
|
+
}];
|
|
7892
|
+
}
|
|
7893
|
+
return [];
|
|
7894
|
+
}
|
|
7895
|
+
const entries = [];
|
|
7896
|
+
const hasToolCalls = !!(msg.toolCalls && msg.toolCalls.length > 0);
|
|
7897
|
+
const hasContent = !!(msg.content && msg.content !== msg.reasoning);
|
|
7898
|
+
const isStreaming = msg.status === "streaming" && isLast;
|
|
7899
|
+
const effectiveReasoning = hasToolCalls && hasContent ? msg.reasoning ? msg.reasoning + "\n" + msg.content : msg.content : msg.reasoning;
|
|
7900
|
+
const effectiveHasContent = hasContent && !hasToolCalls;
|
|
7901
|
+
if (effectiveReasoning) {
|
|
7902
|
+
entries.push({
|
|
7903
|
+
kind: "reasoning",
|
|
7904
|
+
key: `${msg.id}-reasoning`,
|
|
7905
|
+
reasoning: effectiveReasoning,
|
|
7906
|
+
isStreaming: isStreaming && !effectiveHasContent && !hasToolCalls
|
|
7907
|
+
});
|
|
7908
|
+
}
|
|
7909
|
+
if (hasToolCalls) {
|
|
7910
|
+
for (const tc of msg.toolCalls) {
|
|
7911
|
+
if (tc.toolName === "create_artifact") {
|
|
7912
|
+
const resolvedName = parseArgs(tc.args)?.name ?? artifactFallbacks[tc.id];
|
|
7913
|
+
const status = effectiveStatus(tc);
|
|
7914
|
+
if (!resolvedName && status !== "error") continue;
|
|
7915
|
+
entries.push({
|
|
7916
|
+
kind: "tool",
|
|
7917
|
+
key: tc.id,
|
|
7918
|
+
tc,
|
|
7919
|
+
resolvedArtifactName: resolvedName
|
|
7920
|
+
});
|
|
7921
|
+
continue;
|
|
7922
|
+
}
|
|
7923
|
+
if (tc.toolName === "terminal" && tc.status !== "running") {
|
|
7924
|
+
const parsed = parseTerminalResult(tc.result, tc.args);
|
|
7925
|
+
if (parsed && (parsed.exit_code !== 0 || parsed.error)) continue;
|
|
7926
|
+
}
|
|
7927
|
+
entries.push({ kind: "tool", key: tc.id, tc });
|
|
7928
|
+
}
|
|
7929
|
+
}
|
|
7930
|
+
if (effectiveHasContent) {
|
|
7931
|
+
entries.push({
|
|
7932
|
+
kind: "text",
|
|
7933
|
+
key: `${msg.id}-text`,
|
|
7934
|
+
content: msg.content,
|
|
7935
|
+
isStreaming,
|
|
7936
|
+
msg
|
|
7937
|
+
});
|
|
7938
|
+
}
|
|
7939
|
+
const hasRunningTool = hasToolCalls && msg.toolCalls.some(
|
|
7940
|
+
(tc) => tc.status === "running"
|
|
7941
|
+
);
|
|
7942
|
+
if (isStreaming && !effectiveHasContent && !hasRunningTool) {
|
|
7943
|
+
entries.push({ kind: "thinking", key: `${msg.id}-thinking` });
|
|
7944
|
+
}
|
|
7945
|
+
return entries;
|
|
7946
|
+
}
|
|
7947
|
+
function groupBrowserActivityEntries(entries) {
|
|
7948
|
+
const grouped = [];
|
|
7949
|
+
let buffer = [];
|
|
7950
|
+
const flush = () => {
|
|
7951
|
+
if (buffer.length === 0) return;
|
|
7952
|
+
grouped.push({
|
|
7953
|
+
kind: "browser_activity",
|
|
7954
|
+
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
7955
|
+
calls: buffer
|
|
8001
7956
|
});
|
|
7957
|
+
buffer = [];
|
|
8002
7958
|
};
|
|
8003
|
-
|
|
8004
|
-
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
)
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
7959
|
+
for (const entry of entries) {
|
|
7960
|
+
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
7961
|
+
buffer.push(entry.tc);
|
|
7962
|
+
continue;
|
|
7963
|
+
}
|
|
7964
|
+
flush();
|
|
7965
|
+
grouped.push(entry);
|
|
7966
|
+
}
|
|
7967
|
+
flush();
|
|
7968
|
+
return grouped;
|
|
7969
|
+
}
|
|
7970
|
+
function isBrowserToolCall(call) {
|
|
7971
|
+
return call.toolName.startsWith("browser_");
|
|
7972
|
+
}
|
|
7973
|
+
function groupWebSearchEntries(entries) {
|
|
7974
|
+
const grouped = [];
|
|
7975
|
+
let buffer = [];
|
|
7976
|
+
const flush = () => {
|
|
7977
|
+
if (buffer.length === 0) return;
|
|
7978
|
+
if (buffer.length === 1) {
|
|
7979
|
+
grouped.push({ kind: "tool", key: buffer[0].id, tc: buffer[0] });
|
|
7980
|
+
} else {
|
|
7981
|
+
grouped.push({
|
|
7982
|
+
kind: "web_search_group",
|
|
7983
|
+
key: `web-search-${buffer[0].id}-${buffer[buffer.length - 1].id}`,
|
|
7984
|
+
calls: buffer
|
|
7985
|
+
});
|
|
7986
|
+
}
|
|
7987
|
+
buffer = [];
|
|
7988
|
+
};
|
|
7989
|
+
for (const entry of entries) {
|
|
7990
|
+
if (entry.kind === "tool" && entry.tc.toolName === "web_search") {
|
|
7991
|
+
buffer.push(entry.tc);
|
|
7992
|
+
continue;
|
|
7993
|
+
}
|
|
7994
|
+
flush();
|
|
7995
|
+
grouped.push(entry);
|
|
7996
|
+
}
|
|
7997
|
+
flush();
|
|
7998
|
+
return grouped;
|
|
7999
|
+
}
|
|
8000
|
+
function groupMessages(messages) {
|
|
8001
|
+
const groups = [];
|
|
8002
|
+
let pendingSystem = [];
|
|
8003
|
+
const drainPendingAsOrphans = () => {
|
|
8004
|
+
for (const { msg, index } of pendingSystem) {
|
|
8005
|
+
groups.push({ role: "system", messages: [msg], lastGlobalIndex: index });
|
|
8006
|
+
}
|
|
8007
|
+
pendingSystem = [];
|
|
8008
|
+
};
|
|
8009
|
+
for (let i = 0; i < messages.length; i++) {
|
|
8010
|
+
const msg = messages[i];
|
|
8011
|
+
if (msg.role === "system") {
|
|
8012
|
+
pendingSystem.push({ msg, index: i });
|
|
8013
|
+
continue;
|
|
8014
|
+
}
|
|
8015
|
+
if (msg.role === "assistant") {
|
|
8016
|
+
const prev = groups[groups.length - 1];
|
|
8017
|
+
if (prev && prev.role === "assistant" && pendingSystem.length === 0) {
|
|
8018
|
+
prev.messages.push(msg);
|
|
8019
|
+
prev.lastGlobalIndex = i;
|
|
8020
|
+
} else {
|
|
8021
|
+
const folded = pendingSystem.map((p) => p.msg);
|
|
8022
|
+
pendingSystem = [];
|
|
8023
|
+
groups.push({
|
|
8024
|
+
role: "assistant",
|
|
8025
|
+
messages: [...folded, msg],
|
|
8026
|
+
lastGlobalIndex: i
|
|
8027
|
+
});
|
|
8028
|
+
}
|
|
8029
|
+
continue;
|
|
8030
|
+
}
|
|
8031
|
+
drainPendingAsOrphans();
|
|
8032
|
+
groups.push({ role: "user", messages: [msg], lastGlobalIndex: i });
|
|
8033
|
+
}
|
|
8034
|
+
drainPendingAsOrphans();
|
|
8035
|
+
return groups;
|
|
8036
|
+
}
|
|
8037
|
+
function unpackArtifactMeta(systemMeta, fallbackName) {
|
|
8038
|
+
const meta = systemMeta ?? {};
|
|
8039
|
+
return {
|
|
8040
|
+
artifactId: meta.artifact_id ?? "",
|
|
8041
|
+
name: meta.name ?? fallbackName,
|
|
8042
|
+
kind: meta.kind ?? "markdown",
|
|
8043
|
+
version: meta.version ?? 1
|
|
8044
|
+
};
|
|
8045
|
+
}
|
|
8046
|
+
function OrphanSystemMarker({
|
|
8047
|
+
message,
|
|
8048
|
+
sessionId,
|
|
8049
|
+
onRetry
|
|
8050
|
+
}) {
|
|
8051
|
+
if (message.systemKind === "skill_invoked") {
|
|
8052
|
+
const skill = message.systemMeta?.skill ?? message.content;
|
|
8053
|
+
return /* @__PURE__ */ jsxs("div", { className: "my-2 flex items-center gap-2 px-4 text-xs text-foreground/60 ", children: [
|
|
8054
|
+
/* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-emerald-500" }),
|
|
8055
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
8056
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
8057
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground/60 truncate", children: skill })
|
|
8058
|
+
] })
|
|
8059
|
+
] });
|
|
8060
|
+
}
|
|
8061
|
+
if (message.systemKind === "artifact" && sessionId) {
|
|
8062
|
+
const unpacked = unpackArtifactMeta(message.systemMeta, message.content);
|
|
8063
|
+
return /* @__PURE__ */ jsx(
|
|
8064
|
+
ArtifactBlock,
|
|
8065
|
+
{
|
|
8066
|
+
sessionId,
|
|
8067
|
+
artifactId: unpacked.artifactId,
|
|
8068
|
+
name: unpacked.name,
|
|
8069
|
+
kind: unpacked.kind,
|
|
8070
|
+
version: unpacked.version
|
|
8071
|
+
}
|
|
8072
|
+
);
|
|
8073
|
+
}
|
|
8074
|
+
if (message.systemKind === "error" && message.errorInfo) {
|
|
8075
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
8076
|
+
}
|
|
8077
|
+
return null;
|
|
8078
|
+
}
|
|
8079
|
+
function cancelledToolLabel(toolName) {
|
|
8080
|
+
const map = {
|
|
8081
|
+
terminal: "Command",
|
|
8082
|
+
execute_code: "Execute Code",
|
|
8083
|
+
read_file: "Read",
|
|
8084
|
+
write_file: "Write",
|
|
8085
|
+
patch: "Patch",
|
|
8086
|
+
search_files: "Search Files",
|
|
8087
|
+
list_files: "List Files",
|
|
8088
|
+
web_search: "Web Search",
|
|
8089
|
+
web_extract: "Web Fetch",
|
|
8090
|
+
web_crawl: "Web Crawl",
|
|
8091
|
+
session_search: "Session Search",
|
|
8092
|
+
memory: "Memory",
|
|
8093
|
+
todo: "Todo",
|
|
8094
|
+
skills_list: "Skills",
|
|
8095
|
+
skill_view: "Skill",
|
|
8096
|
+
consult_expert: "Expert",
|
|
8097
|
+
delegate_task: "Delegate",
|
|
8098
|
+
ask_user_question: "Ask User Question",
|
|
8099
|
+
process: "Process",
|
|
8100
|
+
create_artifact: "Artifact"
|
|
8101
|
+
};
|
|
8102
|
+
return map[toolName] ?? toolName;
|
|
8103
|
+
}
|
|
8104
|
+
function CancelledToolRow({ tc }) {
|
|
8105
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-sm", children: [
|
|
8106
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground/60", children: cancelledToolLabel(tc.toolName) }),
|
|
8107
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground/60/70", children: "Cancelled" })
|
|
8108
|
+
] });
|
|
8109
|
+
}
|
|
8110
|
+
function TimelineEntryItem({
|
|
8111
|
+
entry,
|
|
8112
|
+
step,
|
|
8113
|
+
sessionId,
|
|
8114
|
+
onFileSelect
|
|
8115
|
+
}) {
|
|
8116
|
+
if (entry.kind === "reasoning") {
|
|
8117
|
+
return /* @__PURE__ */ jsx(ReasoningEntry, { entry, step });
|
|
8118
|
+
}
|
|
8119
|
+
if (entry.kind === "tool") {
|
|
8120
|
+
const rawStatus = effectiveStatus(entry.tc);
|
|
8121
|
+
const hideArtifactFailure = rawStatus === "error" && entry.tc.toolName === "create_artifact";
|
|
8122
|
+
const indicatorStatus = hideArtifactFailure ? "running" : rawStatus;
|
|
8123
|
+
const failureSummary = rawStatus === "error" && !hideArtifactFailure ? toolErrorSummary(entry.tc.result) : "";
|
|
8124
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8125
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8126
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8127
|
+
/* @__PURE__ */ jsx(
|
|
8128
|
+
TimelineIndicator,
|
|
8129
|
+
{
|
|
8130
|
+
className: cn("size-2 border-none", statusColorClass(indicatorStatus))
|
|
8131
|
+
}
|
|
8132
|
+
)
|
|
8033
8133
|
] }),
|
|
8034
|
-
/* @__PURE__ */ jsx(
|
|
8035
|
-
|
|
8134
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: entry.tc.cancelled ? /* @__PURE__ */ jsx(CancelledToolRow, { tc: entry.tc }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
8135
|
+
/* @__PURE__ */ jsx(
|
|
8136
|
+
ToolCallBlock,
|
|
8137
|
+
{
|
|
8138
|
+
tc: entry.tc,
|
|
8139
|
+
resolvedArtifactName: entry.resolvedArtifactName,
|
|
8140
|
+
onFileSelect
|
|
8141
|
+
}
|
|
8142
|
+
),
|
|
8143
|
+
failureSummary ? /* @__PURE__ */ jsx("div", { className: "max-w-full truncate text-xs text-destructive", title: failureSummary, children: failureSummary }) : null
|
|
8144
|
+
] }) })
|
|
8145
|
+
] });
|
|
8146
|
+
}
|
|
8147
|
+
if (entry.kind === "browser_activity") {
|
|
8148
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8149
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8150
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8151
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
8152
|
+
] }),
|
|
8153
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
8154
|
+
] });
|
|
8155
|
+
}
|
|
8156
|
+
if (entry.kind === "web_search_group") {
|
|
8157
|
+
const allComplete = entry.calls.every((tc) => tc.status === "complete");
|
|
8158
|
+
const anyRunning = entry.calls.some((tc) => tc.status === "running");
|
|
8159
|
+
const indicatorClass = anyRunning ? "bg-emerald-500 animate-pulse" : allComplete ? "bg-emerald-500" : "bg-red-500";
|
|
8160
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8161
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8162
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8163
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: cn("size-2 border-none", indicatorClass) })
|
|
8164
|
+
] }),
|
|
8165
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(WebSearchGroupBlock, { tcs: entry.calls }) })
|
|
8166
|
+
] });
|
|
8167
|
+
}
|
|
8168
|
+
if (entry.kind === "text") {
|
|
8169
|
+
return /* @__PURE__ */ jsx(TextEntry, { entry, step });
|
|
8170
|
+
}
|
|
8171
|
+
if (entry.kind === "skill_invoked") {
|
|
8172
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8173
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8174
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8175
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-emerald-500" })
|
|
8176
|
+
] }),
|
|
8177
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 py-1 text-sm ", children: [
|
|
8178
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "Skill" }),
|
|
8179
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground/60 truncate", children: entry.skill }),
|
|
8180
|
+
entry.stagedAt && /* @__PURE__ */ jsxs("span", { className: "text-xs text-foreground/60/70 ", children: [
|
|
8181
|
+
"staged at ",
|
|
8182
|
+
entry.stagedAt
|
|
8183
|
+
] })
|
|
8184
|
+
] }) })
|
|
8185
|
+
] });
|
|
8186
|
+
}
|
|
8187
|
+
if (entry.kind === "artifact") {
|
|
8188
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8189
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8190
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8191
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-sky-500" })
|
|
8192
|
+
] }),
|
|
8193
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: sessionId ? /* @__PURE__ */ jsx(
|
|
8194
|
+
ArtifactBlock,
|
|
8036
8195
|
{
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8196
|
+
sessionId,
|
|
8197
|
+
artifactId: entry.artifactId,
|
|
8198
|
+
name: entry.name,
|
|
8199
|
+
kind: entry.artifactKind,
|
|
8200
|
+
version: entry.version
|
|
8201
|
+
}
|
|
8202
|
+
) : null })
|
|
8203
|
+
] });
|
|
8204
|
+
}
|
|
8205
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8206
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8207
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8208
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-primary animate-pulse" })
|
|
8209
|
+
] }),
|
|
8210
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) })
|
|
8211
|
+
] });
|
|
8212
|
+
}
|
|
8213
|
+
function ReasoningEntry({
|
|
8214
|
+
entry,
|
|
8215
|
+
step
|
|
8216
|
+
}) {
|
|
8217
|
+
const reasoning = useSmoothStream(entry.reasoning, entry.isStreaming);
|
|
8218
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8219
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8220
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8221
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2" })
|
|
8222
|
+
] }),
|
|
8223
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsxs(Reasoning, { isStreaming: entry.isStreaming, children: [
|
|
8224
|
+
/* @__PURE__ */ jsx(ReasoningTrigger, {}),
|
|
8225
|
+
/* @__PURE__ */ jsx(ReasoningContent, { children: reasoning })
|
|
8226
|
+
] }) })
|
|
8227
|
+
] });
|
|
8228
|
+
}
|
|
8229
|
+
function TextEntry({
|
|
8230
|
+
entry,
|
|
8231
|
+
step
|
|
8232
|
+
}) {
|
|
8233
|
+
const content = useSmoothStream(entry.content, entry.isStreaming);
|
|
8234
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
8235
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
8236
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
8237
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/40" })
|
|
8238
|
+
] }),
|
|
8239
|
+
/* @__PURE__ */ jsxs(TimelineContent, { children: [
|
|
8240
|
+
/* @__PURE__ */ jsx(MessageResponse, { children: content }),
|
|
8241
|
+
entry.isFinalTurnText && entry.msg.status === "complete" && /* @__PURE__ */ jsx(TurnFeedback, { msg: entry.msg })
|
|
8242
|
+
] })
|
|
8243
|
+
] });
|
|
8244
|
+
}
|
|
8245
|
+
function deriveIterationLabel(message) {
|
|
8246
|
+
const calls = visibleToolCalls(message);
|
|
8247
|
+
if (calls.length === 0) {
|
|
8248
|
+
return message.reasoning ? "Thought through the problem" : null;
|
|
8249
|
+
}
|
|
8250
|
+
if (calls.length === 1) {
|
|
8251
|
+
const tc = calls[0];
|
|
8252
|
+
return deriveSingleToolLabel(tc);
|
|
8253
|
+
}
|
|
8254
|
+
const firstName = calls[0].toolName;
|
|
8255
|
+
const allSame = calls.every((tc) => tc.toolName === firstName);
|
|
8256
|
+
if (allSame) {
|
|
8257
|
+
const human = cancelledToolLabel(firstName);
|
|
8258
|
+
return `${human} \xD7 ${calls.length}`;
|
|
8259
|
+
}
|
|
8260
|
+
return `Used ${calls.length} tools`;
|
|
8261
|
+
}
|
|
8262
|
+
function deriveSingleToolLabel(tc) {
|
|
8263
|
+
const name = cancelledToolLabel(tc.toolName);
|
|
8264
|
+
if (_HEADER_HIDES_DETAIL.has(tc.toolName)) {
|
|
8265
|
+
return _HEADER_GENERIC_VERB[tc.toolName] ?? name;
|
|
8266
|
+
}
|
|
8267
|
+
const detail = extractToolDetail(tc);
|
|
8268
|
+
return detail ? `${name} \xB7 ${detail}` : name;
|
|
8269
|
+
}
|
|
8270
|
+
var _HEADER_HIDES_DETAIL = /* @__PURE__ */ new Set([
|
|
8271
|
+
"terminal",
|
|
8272
|
+
"execute_code",
|
|
8273
|
+
"memory"
|
|
8274
|
+
]);
|
|
8275
|
+
var _HEADER_GENERIC_VERB = {
|
|
8276
|
+
terminal: "Ran a command",
|
|
8277
|
+
execute_code: "Executed code",
|
|
8278
|
+
memory: "Updated memory"
|
|
8279
|
+
};
|
|
8280
|
+
function extractToolDetail(tc) {
|
|
8281
|
+
const args = parseArgs(tc.args);
|
|
8282
|
+
if (!args) return null;
|
|
8283
|
+
const stringArg = (key) => {
|
|
8284
|
+
const v = args[key];
|
|
8285
|
+
return typeof v === "string" && v.length > 0 ? v : null;
|
|
8286
|
+
};
|
|
8287
|
+
switch (tc.toolName) {
|
|
8288
|
+
case "read_file":
|
|
8289
|
+
case "write_file":
|
|
8290
|
+
case "patch":
|
|
8291
|
+
case "list_files":
|
|
8292
|
+
case "search_files": {
|
|
8293
|
+
const path = stringArg("path") ?? stringArg("file_path");
|
|
8294
|
+
return path ? lastPathSegment(path) : null;
|
|
8295
|
+
}
|
|
8296
|
+
case "terminal": {
|
|
8297
|
+
const cmd = stringArg("command");
|
|
8298
|
+
return cmd ? truncate2(cmd, 40) : null;
|
|
8299
|
+
}
|
|
8300
|
+
case "execute_code": {
|
|
8301
|
+
const code3 = stringArg("code");
|
|
8302
|
+
return code3 ? truncate2(code3.split("\n")[0] ?? "", 40) : null;
|
|
8303
|
+
}
|
|
8304
|
+
case "web_search":
|
|
8305
|
+
case "web_crawl":
|
|
8306
|
+
return stringArg("query");
|
|
8307
|
+
case "web_extract":
|
|
8308
|
+
return stringArg("url");
|
|
8309
|
+
case "skill_view":
|
|
8310
|
+
case "skill_manage":
|
|
8311
|
+
return stringArg("name") ?? stringArg("skill");
|
|
8312
|
+
case "create_artifact":
|
|
8313
|
+
case "consult_expert":
|
|
8314
|
+
case "delegate_task":
|
|
8315
|
+
return stringArg("name") ?? stringArg("task") ?? stringArg("title");
|
|
8316
|
+
case "memory":
|
|
8317
|
+
return stringArg("action") ?? stringArg("key");
|
|
8318
|
+
default:
|
|
8319
|
+
return null;
|
|
8320
|
+
}
|
|
8321
|
+
}
|
|
8322
|
+
function lastPathSegment(path) {
|
|
8323
|
+
const cleaned = path.replace(/\/+$/, "");
|
|
8324
|
+
const idx = cleaned.lastIndexOf("/");
|
|
8325
|
+
return idx >= 0 ? cleaned.slice(idx + 1) : cleaned;
|
|
8326
|
+
}
|
|
8327
|
+
function truncate2(s, max) {
|
|
8328
|
+
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
8329
|
+
}
|
|
8330
|
+
var _SIMPLE_MODE_HIDDEN_TOOLS = /* @__PURE__ */ new Set([
|
|
8331
|
+
"list_files",
|
|
8332
|
+
"search_files",
|
|
8333
|
+
"session_search",
|
|
8334
|
+
"skills_list",
|
|
8335
|
+
"process",
|
|
8336
|
+
"memory",
|
|
8337
|
+
// Shell commands and code execution are infrastructure plumbing the
|
|
8338
|
+
// user doesn't need to see when the goal is to know *what* the
|
|
8339
|
+
// agent accomplished, not *how*. Expert mode still has the full
|
|
8340
|
+
// command + output block.
|
|
8341
|
+
"terminal",
|
|
8342
|
+
"execute_code"
|
|
8343
|
+
]);
|
|
8344
|
+
function _isHiddenSimpleTool(tc) {
|
|
8345
|
+
if (_SIMPLE_MODE_HIDDEN_TOOLS.has(tc.toolName)) return true;
|
|
8346
|
+
if (tc.toolName.startsWith("browser_")) return true;
|
|
8347
|
+
return false;
|
|
8348
|
+
}
|
|
8349
|
+
function visibleToolCalls(message) {
|
|
8350
|
+
return (message.toolCalls ?? []).filter((tc) => {
|
|
8351
|
+
if (_isHiddenSimpleTool(tc)) return false;
|
|
8352
|
+
const status = effectiveStatus(tc);
|
|
8353
|
+
if (status === "error" || status === "cancelled") return false;
|
|
8354
|
+
return true;
|
|
8355
|
+
});
|
|
8356
|
+
}
|
|
8357
|
+
function isIterationLive(message) {
|
|
8358
|
+
const calls = message.toolCalls ?? [];
|
|
8359
|
+
if (calls.length > 0) {
|
|
8360
|
+
return calls.some((tc) => tc.status === "running");
|
|
8361
|
+
}
|
|
8362
|
+
return message.status === "streaming";
|
|
8363
|
+
}
|
|
8364
|
+
function liveIterationLabel(message) {
|
|
8365
|
+
const running = (message.toolCalls ?? []).filter(
|
|
8366
|
+
(tc) => tc.status === "running" && !_isHiddenSimpleTool(tc)
|
|
8367
|
+
);
|
|
8368
|
+
if (running.length === 0) return "Thinking\u2026";
|
|
8369
|
+
if (running.length === 1) {
|
|
8370
|
+
const tc = running[0];
|
|
8371
|
+
const name = cancelledToolLabel(tc.toolName);
|
|
8372
|
+
const detail = extractToolDetail(tc);
|
|
8373
|
+
return detail ? `Running ${name} \xB7 ${detail}\u2026` : `Running ${name}\u2026`;
|
|
8374
|
+
}
|
|
8375
|
+
const firstName = running[0].toolName;
|
|
8376
|
+
const allSame = running.every((tc) => tc.toolName === firstName);
|
|
8377
|
+
if (allSame) {
|
|
8378
|
+
return `Running ${cancelledToolLabel(firstName)} \xD7 ${running.length}\u2026`;
|
|
8379
|
+
}
|
|
8380
|
+
return `Running ${running.length} tools\u2026`;
|
|
8381
|
+
}
|
|
8382
|
+
var _TOOL_ROW_ICON = {
|
|
8383
|
+
read_file: FileTextIcon,
|
|
8384
|
+
write_file: FileTextIcon,
|
|
8385
|
+
patch: FileEditIcon,
|
|
8386
|
+
list_files: ListIcon,
|
|
8387
|
+
search_files: SearchIcon,
|
|
8388
|
+
terminal: TerminalIcon,
|
|
8389
|
+
execute_code: TerminalIcon,
|
|
8390
|
+
web_search: GlobeIcon,
|
|
8391
|
+
web_extract: GlobeIcon,
|
|
8392
|
+
web_crawl: GlobeIcon,
|
|
8393
|
+
session_search: SearchIcon,
|
|
8394
|
+
skill_view: BookOpenIcon,
|
|
8395
|
+
skills_list: BookOpenIcon,
|
|
8396
|
+
skill_manage: PenLineIcon,
|
|
8397
|
+
consult_expert: SparklesIcon,
|
|
8398
|
+
delegate_task: ArrowRight,
|
|
8399
|
+
create_artifact: FileTextIcon,
|
|
8400
|
+
memory: PenLineIcon,
|
|
8401
|
+
todo: ListIcon
|
|
8402
|
+
};
|
|
8403
|
+
function _toolRowIcon(toolName) {
|
|
8404
|
+
return _TOOL_ROW_ICON[toolName] ?? WrenchIcon;
|
|
8405
|
+
}
|
|
8406
|
+
function _toolRowLabel(tc) {
|
|
8407
|
+
const detail = extractToolDetail(tc);
|
|
8408
|
+
switch (tc.toolName) {
|
|
8409
|
+
case "read_file":
|
|
8410
|
+
return detail ? `Read ${detail}` : "Read a file";
|
|
8411
|
+
case "write_file":
|
|
8412
|
+
return detail ? `Wrote ${detail}` : "Wrote a file";
|
|
8413
|
+
case "patch":
|
|
8414
|
+
return detail ? `Edited ${detail}` : "Edited a file";
|
|
8415
|
+
case "list_files":
|
|
8416
|
+
return detail ? `Listed ${detail}` : "Listed files";
|
|
8417
|
+
case "search_files":
|
|
8418
|
+
return detail ? `Searched files for "${detail}"` : "Searched files";
|
|
8419
|
+
case "terminal":
|
|
8420
|
+
return "Ran a command";
|
|
8421
|
+
case "execute_code":
|
|
8422
|
+
return "Executed code";
|
|
8423
|
+
case "web_search":
|
|
8424
|
+
return detail ? `Searched the web for "${detail}"` : "Searched the web";
|
|
8425
|
+
case "web_crawl":
|
|
8426
|
+
return detail ? `Crawled "${detail}"` : "Crawled the web";
|
|
8427
|
+
case "web_extract":
|
|
8428
|
+
return detail ? `Fetched ${detail}` : "Fetched a page";
|
|
8429
|
+
case "session_search":
|
|
8430
|
+
return detail ? `Searched session for "${detail}"` : "Searched session";
|
|
8431
|
+
case "skill_view":
|
|
8432
|
+
return detail ? `Read the ${detail} skill` : "Read a skill";
|
|
8433
|
+
case "skills_list":
|
|
8434
|
+
return "Listed available skills";
|
|
8435
|
+
case "skill_manage":
|
|
8436
|
+
return detail ? `Updated skill ${detail}` : "Managed skills";
|
|
8437
|
+
case "consult_expert":
|
|
8438
|
+
return detail ? `Consulted ${detail} expert` : "Consulted an expert";
|
|
8439
|
+
case "delegate_task":
|
|
8440
|
+
return detail ? `Delegated: ${detail}` : "Delegated a task";
|
|
8441
|
+
case "create_artifact":
|
|
8442
|
+
return detail ? `Created artifact "${detail}"` : "Created an artifact";
|
|
8443
|
+
case "memory":
|
|
8444
|
+
return detail ? `Memory ${detail}` : "Updated memory";
|
|
8445
|
+
case "todo":
|
|
8446
|
+
return detail ? `Todo ${detail}` : "Updated todo list";
|
|
8447
|
+
default:
|
|
8448
|
+
return cancelledToolLabel(tc.toolName);
|
|
8449
|
+
}
|
|
8450
|
+
}
|
|
8451
|
+
function SimpleDetailRow({ icon: Icon, children }) {
|
|
8452
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 text-sm", children: [
|
|
8453
|
+
/* @__PURE__ */ jsx(
|
|
8454
|
+
Icon,
|
|
8455
|
+
{
|
|
8456
|
+
className: "mt-0.5 size-4 shrink-0 text-foreground/60",
|
|
8457
|
+
"aria-hidden": true
|
|
8458
|
+
}
|
|
8459
|
+
),
|
|
8460
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 leading-relaxed text-foreground/60", children })
|
|
8461
|
+
] });
|
|
8462
|
+
}
|
|
8463
|
+
function ClampedReasoning({
|
|
8464
|
+
text,
|
|
8465
|
+
previewParagraphs = 2
|
|
8466
|
+
}) {
|
|
8467
|
+
const paragraphs = splitReasoningParagraphs(text);
|
|
8468
|
+
const [expanded, setExpanded] = useState(false);
|
|
8469
|
+
const hasMore = paragraphs.length > previewParagraphs;
|
|
8470
|
+
const visible = expanded || !hasMore ? paragraphs : paragraphs.slice(0, previewParagraphs);
|
|
8471
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
8472
|
+
visible.map((paragraph, i) => /* @__PURE__ */ jsx("p", { className: "whitespace-pre-wrap", children: paragraph }, i)),
|
|
8473
|
+
hasMore && /* @__PURE__ */ jsx(
|
|
8474
|
+
"button",
|
|
8475
|
+
{
|
|
8476
|
+
type: "button",
|
|
8477
|
+
onClick: () => setExpanded((prev) => !prev),
|
|
8478
|
+
className: "text-xs font-medium text-foreground hover:text-foreground/70 cursor-pointer",
|
|
8479
|
+
children: expanded ? "Show less" : "Show more..."
|
|
8480
|
+
}
|
|
8481
|
+
)
|
|
8482
|
+
] });
|
|
8483
|
+
}
|
|
8484
|
+
function splitReasoningParagraphs(text) {
|
|
8485
|
+
const trimmed = text.trim();
|
|
8486
|
+
if (!trimmed) return [];
|
|
8487
|
+
const blankSplit = trimmed.split(/\n\s*\n+/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
8488
|
+
if (blankSplit.length > 1) return blankSplit;
|
|
8489
|
+
return trimmed.split(/\n+/).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
8490
|
+
}
|
|
8491
|
+
function IterationExpanded({
|
|
8492
|
+
message
|
|
8493
|
+
}) {
|
|
8494
|
+
const calls = visibleToolCalls(message);
|
|
8495
|
+
const reasoning = (message.reasoning ?? "").trim();
|
|
8496
|
+
const anyVisibleRunning = calls.some((tc) => tc.status === "running");
|
|
8497
|
+
const showDone = !anyVisibleRunning && (calls.length > 0 || !!reasoning);
|
|
8498
|
+
if (!reasoning && calls.length === 0) return null;
|
|
8499
|
+
return /* @__PURE__ */ jsxs("div", { className: "ml-2 space-y-3 border-l border-border/40 pl-4 py-1", children: [
|
|
8500
|
+
reasoning && /* @__PURE__ */ jsx(SimpleDetailRow, { icon: ClockIcon, children: /* @__PURE__ */ jsx(ClampedReasoning, { text: reasoning }) }),
|
|
8501
|
+
calls.map((tc) => {
|
|
8502
|
+
if (tc.toolName === "todo") {
|
|
8503
|
+
return /* @__PURE__ */ jsx("div", { className: "pr-1", children: /* @__PURE__ */ jsx(TodoToolBlock, { tc }) }, tc.id);
|
|
8504
|
+
}
|
|
8505
|
+
return /* @__PURE__ */ jsx(SimpleDetailRow, { icon: _toolRowIcon(tc.toolName), children: /* @__PURE__ */ jsx("span", { children: _toolRowLabel(tc) }) }, tc.id);
|
|
8506
|
+
}),
|
|
8507
|
+
showDone && /* @__PURE__ */ jsx(SimpleDetailRow, { icon: CircleCheckIcon, children: /* @__PURE__ */ jsx("span", { className: "text-foreground", children: "Done" }) })
|
|
8508
|
+
] });
|
|
8509
|
+
}
|
|
8510
|
+
function IterationGroup({
|
|
8511
|
+
message,
|
|
8512
|
+
sessionId,
|
|
8513
|
+
artifactFallbacks,
|
|
8514
|
+
onFileSelect
|
|
8515
|
+
}) {
|
|
8516
|
+
const summary = message.iterationSummary?.summary;
|
|
8517
|
+
const [open, setOpen] = useState(false);
|
|
8518
|
+
if (isIterationLive(message)) {
|
|
8519
|
+
const askCall = (message.toolCalls ?? []).find(
|
|
8520
|
+
(tc) => tc.toolName === "ask_user_question" && tc.status === "running"
|
|
8521
|
+
);
|
|
8522
|
+
if (askCall) {
|
|
8523
|
+
return /* @__PURE__ */ jsx("div", { className: "px-1 py-0.5", children: /* @__PURE__ */ jsx(AskUserQuestionToolBlock, { tc: askCall }) });
|
|
8524
|
+
}
|
|
8525
|
+
const label2 = liveIterationLabel(message);
|
|
8526
|
+
return /* @__PURE__ */ jsx("div", { className: "px-1 py-0.5 text-sm", children: /* @__PURE__ */ jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: label2 }) });
|
|
8527
|
+
}
|
|
8528
|
+
const label = summary ?? deriveIterationLabel(message);
|
|
8529
|
+
if (!label) {
|
|
8530
|
+
return null;
|
|
8531
|
+
}
|
|
8532
|
+
const labelTone = summary ? "text-foreground/80" : "text-foreground/50";
|
|
8533
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
8534
|
+
/* @__PURE__ */ jsxs(
|
|
8535
|
+
"button",
|
|
8536
|
+
{
|
|
8537
|
+
type: "button",
|
|
8538
|
+
onClick: () => setOpen((prev) => !prev),
|
|
8539
|
+
"aria-expanded": open,
|
|
8540
|
+
className: "flex w-full items-center gap-2 rounded px-1 py-0.5 text-left text-sm hover:bg-muted/40",
|
|
8541
|
+
children: [
|
|
8542
|
+
/* @__PURE__ */ jsx("span", { className: cn("flex-1 truncate", labelTone), children: label }),
|
|
8543
|
+
/* @__PURE__ */ jsx(
|
|
8544
|
+
ChevronDown,
|
|
8545
|
+
{
|
|
8546
|
+
className: cn(
|
|
8547
|
+
"size-3 shrink-0 text-foreground/60 transition-transform",
|
|
8548
|
+
open && "rotate-180"
|
|
8549
|
+
),
|
|
8550
|
+
"aria-hidden": true
|
|
8551
|
+
}
|
|
8552
|
+
)
|
|
8553
|
+
]
|
|
8554
|
+
}
|
|
8555
|
+
),
|
|
8556
|
+
open && /* @__PURE__ */ jsx(
|
|
8557
|
+
IterationExpanded,
|
|
8558
|
+
{
|
|
8559
|
+
message,
|
|
8560
|
+
sessionId,
|
|
8561
|
+
artifactFallbacks,
|
|
8562
|
+
onFileSelect
|
|
8563
|
+
}
|
|
8564
|
+
)
|
|
8565
|
+
] });
|
|
8566
|
+
}
|
|
8567
|
+
function deriveFileArtifactsFromMessages(messages) {
|
|
8568
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8569
|
+
const out = [];
|
|
8570
|
+
for (const msg of messages) {
|
|
8571
|
+
if (msg.role !== "assistant" || !msg.toolCalls) continue;
|
|
8572
|
+
for (const tc of msg.toolCalls) {
|
|
8573
|
+
const status = effectiveStatus(tc);
|
|
8574
|
+
if (status === "error" || status === "cancelled") continue;
|
|
8575
|
+
const args = parseArgs(tc.args);
|
|
8576
|
+
if (!args) continue;
|
|
8577
|
+
if (tc.toolName === "write_file" || tc.toolName === "patch") {
|
|
8578
|
+
const path = typeof args.path === "string" ? args.path : typeof args.file_path === "string" ? args.file_path : "";
|
|
8579
|
+
if (!path || seen.has(`file:${path}`)) continue;
|
|
8580
|
+
seen.add(`file:${path}`);
|
|
8581
|
+
out.push({
|
|
8582
|
+
kind: "file",
|
|
8583
|
+
label: path.split("/").pop() || path,
|
|
8584
|
+
ref: path
|
|
8585
|
+
});
|
|
8586
|
+
continue;
|
|
8587
|
+
}
|
|
8588
|
+
if (tc.toolName === "create_artifact") {
|
|
8589
|
+
const name = typeof args.name === "string" ? args.name : "";
|
|
8590
|
+
if (!name || seen.has(`artifact:${name}`)) continue;
|
|
8591
|
+
seen.add(`artifact:${name}`);
|
|
8592
|
+
out.push({
|
|
8593
|
+
kind: "artifact",
|
|
8594
|
+
label: name,
|
|
8595
|
+
ref: name
|
|
8596
|
+
});
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
}
|
|
8600
|
+
return out;
|
|
8601
|
+
}
|
|
8602
|
+
function SimpleAssistantGroup({
|
|
8603
|
+
messages,
|
|
8604
|
+
lastGlobalIndex,
|
|
8605
|
+
totalMessages,
|
|
8606
|
+
isRunning,
|
|
8607
|
+
sessionId,
|
|
8608
|
+
artifactFallbacks,
|
|
8609
|
+
onFileSelect,
|
|
8610
|
+
onRetry
|
|
8611
|
+
}) {
|
|
8612
|
+
const assistantMessages = messages.filter((m) => m.role === "assistant");
|
|
8613
|
+
const tail = assistantMessages[assistantMessages.length - 1];
|
|
8614
|
+
const tailHasTools = !!(tail?.toolCalls && tail.toolCalls.length > 0);
|
|
8615
|
+
const tailIsTextOnly = !!tail && !tailHasTools;
|
|
8616
|
+
const finalText = tailIsTextOnly && tail.content ? tail.content : "";
|
|
8617
|
+
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
8618
|
+
const showThinkingShim = isTailGroup && isRunning && (!tail && messages.some((m) => m.role !== "assistant") || tailIsTextOnly && tail.status === "streaming" && !tail.content);
|
|
8619
|
+
const showErrorInfo = !!tail && tail.status === "error" && !!tail.errorInfo;
|
|
8620
|
+
const effectiveTurnSummary = (() => {
|
|
8621
|
+
const fromHarness = tail?.turnSummary;
|
|
8622
|
+
if (fromHarness && fromHarness.artifacts.length > 0) {
|
|
8623
|
+
return fromHarness;
|
|
8624
|
+
}
|
|
8625
|
+
const derived = deriveFileArtifactsFromMessages(messages);
|
|
8626
|
+
if (derived.length === 0) return fromHarness;
|
|
8627
|
+
return {
|
|
8628
|
+
turnId: fromHarness?.turnId ?? "",
|
|
8629
|
+
recap: fromHarness?.recap ?? "",
|
|
8630
|
+
artifacts: derived
|
|
8631
|
+
};
|
|
8632
|
+
})();
|
|
8633
|
+
return /* @__PURE__ */ jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxs(MessageContent, { children: [
|
|
8634
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
8635
|
+
messages.map((message) => {
|
|
8636
|
+
if (message.role === "system") {
|
|
8637
|
+
return /* @__PURE__ */ jsx(
|
|
8638
|
+
OrphanSystemMarker,
|
|
8639
|
+
{
|
|
8640
|
+
message,
|
|
8641
|
+
sessionId,
|
|
8642
|
+
onRetry: void 0
|
|
8643
|
+
},
|
|
8644
|
+
message.id
|
|
8645
|
+
);
|
|
8646
|
+
}
|
|
8647
|
+
if (message === tail && tailIsTextOnly) return null;
|
|
8648
|
+
return /* @__PURE__ */ jsx(
|
|
8649
|
+
IterationGroup,
|
|
8650
|
+
{
|
|
8651
|
+
message,
|
|
8652
|
+
sessionId,
|
|
8653
|
+
artifactFallbacks,
|
|
8654
|
+
onFileSelect
|
|
8655
|
+
},
|
|
8656
|
+
message.id
|
|
8657
|
+
);
|
|
8658
|
+
}),
|
|
8659
|
+
showThinkingShim && /* @__PURE__ */ jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." })
|
|
8660
|
+
] }),
|
|
8661
|
+
finalText && /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
|
|
8662
|
+
/* @__PURE__ */ jsx(MessageResponse, { children: finalText }),
|
|
8663
|
+
tail?.status === "complete" && /* @__PURE__ */ jsx(TurnFeedback, { msg: tail })
|
|
8664
|
+
] }),
|
|
8665
|
+
effectiveTurnSummary && /* @__PURE__ */ jsx(
|
|
8666
|
+
TurnSummaryCard,
|
|
8667
|
+
{
|
|
8668
|
+
summary: effectiveTurnSummary,
|
|
8669
|
+
sessionId,
|
|
8670
|
+
messages,
|
|
8671
|
+
onFileSelect
|
|
8672
|
+
}
|
|
8673
|
+
),
|
|
8674
|
+
showErrorInfo && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
|
|
8675
|
+
] }) });
|
|
8676
|
+
}
|
|
8677
|
+
function AssistantGroup({
|
|
8678
|
+
messages,
|
|
8679
|
+
lastGlobalIndex,
|
|
8680
|
+
totalMessages,
|
|
8681
|
+
isRunning,
|
|
8682
|
+
sessionId,
|
|
8683
|
+
artifactFallbacks,
|
|
8684
|
+
onFileSelect,
|
|
8685
|
+
onRetry,
|
|
8686
|
+
viewMode = "simple"
|
|
8687
|
+
}) {
|
|
8688
|
+
if (viewMode === "simple") {
|
|
8689
|
+
return /* @__PURE__ */ jsx(
|
|
8690
|
+
SimpleAssistantGroup,
|
|
8691
|
+
{
|
|
8692
|
+
messages,
|
|
8693
|
+
lastGlobalIndex,
|
|
8694
|
+
totalMessages,
|
|
8695
|
+
isRunning,
|
|
8696
|
+
sessionId,
|
|
8697
|
+
artifactFallbacks,
|
|
8698
|
+
onFileSelect,
|
|
8699
|
+
onRetry
|
|
8700
|
+
}
|
|
8701
|
+
);
|
|
8702
|
+
}
|
|
8703
|
+
let entries = [];
|
|
8704
|
+
for (let i = 0; i < messages.length; i++) {
|
|
8705
|
+
const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
|
|
8706
|
+
entries.push(...messageToEntries(messages[i], isLast, artifactFallbacks));
|
|
8707
|
+
}
|
|
8708
|
+
entries = groupBrowserActivityEntries(entries);
|
|
8709
|
+
entries = groupWebSearchEntries(entries);
|
|
8710
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
8711
|
+
const entry = entries[i];
|
|
8712
|
+
if (entry?.kind === "text") {
|
|
8713
|
+
entries[i] = { ...entry, isFinalTurnText: true };
|
|
8714
|
+
break;
|
|
8715
|
+
}
|
|
8716
|
+
}
|
|
8717
|
+
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
8718
|
+
const lastEntry = entries[entries.length - 1];
|
|
8719
|
+
const hasRunningTool = entries.some(
|
|
8720
|
+
(e) => e.kind === "tool" && e.tc.status === "running"
|
|
8721
|
+
);
|
|
8722
|
+
const tailMsg = messages[messages.length - 1];
|
|
8723
|
+
if (isTailGroup && isRunning && !hasRunningTool && lastEntry?.kind !== "thinking") {
|
|
8724
|
+
entries.push({ kind: "thinking", key: `${tailMsg.id}-tail-thinking` });
|
|
8725
|
+
}
|
|
8726
|
+
const tail = messages[messages.length - 1];
|
|
8727
|
+
const showErrorInfo = tail && tail.role === "assistant" && tail.status === "error" && !!tail.errorInfo;
|
|
8728
|
+
return /* @__PURE__ */ jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsxs(MessageContent, { children: [
|
|
8729
|
+
/* @__PURE__ */ jsx(Timeline, { defaultValue: 999, className: "gap-0", children: entries.map((entry, i) => /* @__PURE__ */ jsx(
|
|
8730
|
+
TimelineEntryItem,
|
|
8731
|
+
{
|
|
8732
|
+
entry,
|
|
8733
|
+
step: i + 1,
|
|
8734
|
+
sessionId,
|
|
8735
|
+
onFileSelect
|
|
8736
|
+
},
|
|
8737
|
+
entry.key
|
|
8738
|
+
)) }),
|
|
8739
|
+
showErrorInfo && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: tail.errorInfo, onRetry }) })
|
|
8740
|
+
] }) });
|
|
8741
|
+
}
|
|
8742
|
+
function RetryBanner({ indicator }) {
|
|
8743
|
+
const [open, setOpen] = useState(false);
|
|
8744
|
+
return /* @__PURE__ */ jsxs(
|
|
8745
|
+
"div",
|
|
8746
|
+
{
|
|
8747
|
+
role: "status",
|
|
8748
|
+
className: "flex flex-col gap-1 border-l-2 border-amber-500 bg-amber-500/5 px-3 py-2 text-xs",
|
|
8749
|
+
children: [
|
|
8750
|
+
/* @__PURE__ */ jsxs(
|
|
8751
|
+
"button",
|
|
8752
|
+
{
|
|
8753
|
+
type: "button",
|
|
8754
|
+
onClick: () => setOpen((prev) => !prev),
|
|
8755
|
+
className: "flex items-center gap-2 text-left text-amber-600 hover:text-amber-700",
|
|
8756
|
+
"aria-expanded": open,
|
|
8757
|
+
children: [
|
|
8758
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "size-3 shrink-0" }),
|
|
8759
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate font-medium", children: indicator.title }),
|
|
8760
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[10px] text-foreground/60", children: [
|
|
8761
|
+
"attempt ",
|
|
8762
|
+
indicator.attempt
|
|
8763
|
+
] }),
|
|
8764
|
+
indicator.detail && (open ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3" }))
|
|
8765
|
+
]
|
|
8766
|
+
}
|
|
8767
|
+
),
|
|
8768
|
+
open && indicator.detail && /* @__PURE__ */ jsx("pre", { className: "mt-1 overflow-x-auto rounded-none bg-background p-2 font-mono text-[11px] whitespace-pre-wrap wrap-break-word text-foreground/60", children: indicator.detail })
|
|
8769
|
+
]
|
|
8770
|
+
}
|
|
8771
|
+
);
|
|
8772
|
+
}
|
|
8773
|
+
function ChatThread({
|
|
8774
|
+
sessionId,
|
|
8775
|
+
messages,
|
|
8776
|
+
isRunning,
|
|
8777
|
+
isLoadingHistory = false,
|
|
8778
|
+
onSend,
|
|
8779
|
+
onStop,
|
|
8780
|
+
onFileSelect,
|
|
8781
|
+
disabled = false,
|
|
8782
|
+
disabledReason,
|
|
8783
|
+
tokenUsage,
|
|
8784
|
+
retryIndicator,
|
|
8785
|
+
onRetry,
|
|
8786
|
+
onComposerError,
|
|
8787
|
+
showBrowser = false,
|
|
8788
|
+
onToggleBrowser,
|
|
8789
|
+
showWorkspace = false,
|
|
8790
|
+
onToggleWorkspace,
|
|
8791
|
+
canShowBrowser = false,
|
|
8792
|
+
canShowWorkspace = false,
|
|
8793
|
+
viewMode = "simple",
|
|
8794
|
+
onViewModeChange
|
|
8795
|
+
}) {
|
|
8796
|
+
const groups = useMemo(() => groupMessages(messages), [messages]);
|
|
8797
|
+
const artifactFallbacks = useMemo(() => {
|
|
8798
|
+
const fallbacks = {};
|
|
8799
|
+
const createArtifactToolCallIds = [];
|
|
8800
|
+
let artifactIdx = 0;
|
|
8801
|
+
for (const msg of messages) {
|
|
8802
|
+
if (msg.role === "assistant" && msg.toolCalls) {
|
|
8803
|
+
for (const tc of msg.toolCalls) {
|
|
8804
|
+
if (tc.toolName === "create_artifact" && !tc.cancelled && tc.status !== "error") {
|
|
8805
|
+
createArtifactToolCallIds.push(tc.id);
|
|
8806
|
+
}
|
|
8045
8807
|
}
|
|
8046
|
-
)
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
type: "button",
|
|
8052
|
-
variant: "ghost",
|
|
8053
|
-
size: "icon-xs",
|
|
8054
|
-
onClick: () => setViewerScale(scale - 0.1),
|
|
8055
|
-
disabled: scale <= 0.5,
|
|
8056
|
-
"aria-label": "Zoom out PDF",
|
|
8057
|
-
title: "Zoom out",
|
|
8058
|
-
children: /* @__PURE__ */ jsx(MinusIcon, { className: "size-3.5" })
|
|
8808
|
+
} else if (msg.role === "system" && msg.systemKind === "artifact") {
|
|
8809
|
+
const tcId = createArtifactToolCallIds[artifactIdx];
|
|
8810
|
+
if (tcId) {
|
|
8811
|
+
const { name } = unpackArtifactMeta(msg.systemMeta, msg.content);
|
|
8812
|
+
if (name) fallbacks[tcId] = name;
|
|
8059
8813
|
}
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8814
|
+
artifactIdx += 1;
|
|
8815
|
+
}
|
|
8816
|
+
}
|
|
8817
|
+
return fallbacks;
|
|
8818
|
+
}, [messages]);
|
|
8819
|
+
const activeFailureId = useMemo(() => {
|
|
8820
|
+
if (messages.length === 0) return null;
|
|
8821
|
+
const tail = messages[messages.length - 1];
|
|
8822
|
+
if (tail.role === "system" && tail.systemKind === "error" && tail.errorInfo) {
|
|
8823
|
+
return tail.id;
|
|
8824
|
+
}
|
|
8825
|
+
if (tail.role === "assistant" && tail.status === "error" && tail.errorInfo) {
|
|
8826
|
+
return tail.id;
|
|
8827
|
+
}
|
|
8828
|
+
return null;
|
|
8829
|
+
}, [messages]);
|
|
8830
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden bg-background text-sm", children: [
|
|
8831
|
+
/* @__PURE__ */ jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
|
|
8832
|
+
/* @__PURE__ */ jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsx(
|
|
8833
|
+
ConversationEmptyState,
|
|
8063
8834
|
{
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
const viewer = pdfViewerRef.current;
|
|
8068
|
-
if (!viewer) return;
|
|
8069
|
-
viewer.currentScaleValue = "page-width";
|
|
8070
|
-
setScale(viewer.currentScale || 1);
|
|
8071
|
-
},
|
|
8072
|
-
"aria-label": "Fit PDF to width",
|
|
8073
|
-
title: "Fit width",
|
|
8074
|
-
children: [
|
|
8075
|
-
Math.round(scale * 100),
|
|
8076
|
-
"%"
|
|
8077
|
-
]
|
|
8835
|
+
icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
8836
|
+
title: "Loading conversation",
|
|
8837
|
+
description: "Fetching the session history."
|
|
8078
8838
|
}
|
|
8079
|
-
)
|
|
8080
|
-
|
|
8081
|
-
Button,
|
|
8839
|
+
) : messages.length === 0 && !disabled ? /* @__PURE__ */ jsx(
|
|
8840
|
+
ConversationEmptyState,
|
|
8082
8841
|
{
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
onClick: () => setViewerScale(scale + 0.1),
|
|
8087
|
-
disabled: scale >= 3,
|
|
8088
|
-
"aria-label": "Zoom in PDF",
|
|
8089
|
-
title: "Zoom in",
|
|
8090
|
-
children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-3.5" })
|
|
8842
|
+
icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
8843
|
+
title: "Start a conversation",
|
|
8844
|
+
description: "Ask me anything \u2014 I can search, analyze, write code, and more."
|
|
8091
8845
|
}
|
|
8092
|
-
),
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8846
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8847
|
+
groups.map((group) => {
|
|
8848
|
+
if (group.role === "user") {
|
|
8849
|
+
const msg = group.messages[0];
|
|
8850
|
+
return /* @__PURE__ */ jsx(
|
|
8851
|
+
ChatMessage,
|
|
8852
|
+
{
|
|
8853
|
+
message: msg,
|
|
8854
|
+
onFileSelect
|
|
8855
|
+
},
|
|
8856
|
+
msg.id
|
|
8857
|
+
);
|
|
8858
|
+
}
|
|
8859
|
+
if (group.role === "system") {
|
|
8860
|
+
const msg = group.messages[0];
|
|
8861
|
+
const groupRetry2 = msg.id === activeFailureId ? onRetry : void 0;
|
|
8862
|
+
return /* @__PURE__ */ jsx(
|
|
8863
|
+
OrphanSystemMarker,
|
|
8864
|
+
{
|
|
8865
|
+
message: msg,
|
|
8866
|
+
sessionId,
|
|
8867
|
+
onRetry: groupRetry2
|
|
8868
|
+
},
|
|
8869
|
+
msg.id
|
|
8870
|
+
);
|
|
8871
|
+
}
|
|
8872
|
+
const groupTail = group.messages[group.messages.length - 1];
|
|
8873
|
+
const groupRetry = groupTail.id === activeFailureId ? onRetry : void 0;
|
|
8874
|
+
return /* @__PURE__ */ jsx(
|
|
8875
|
+
AssistantGroup,
|
|
8876
|
+
{
|
|
8877
|
+
messages: group.messages,
|
|
8878
|
+
lastGlobalIndex: group.lastGlobalIndex,
|
|
8879
|
+
totalMessages: messages.length,
|
|
8880
|
+
isRunning,
|
|
8881
|
+
sessionId,
|
|
8882
|
+
artifactFallbacks,
|
|
8883
|
+
onFileSelect,
|
|
8884
|
+
onRetry: groupRetry,
|
|
8885
|
+
viewMode
|
|
8886
|
+
},
|
|
8887
|
+
group.messages[0].id
|
|
8888
|
+
);
|
|
8889
|
+
}),
|
|
8890
|
+
isRunning && messages.length > 0 && messages[messages.length - 1].role === "user" && /* @__PURE__ */ jsx(Message, { from: "assistant", children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Shimmer, { duration: 3, spread: 3, className: "text-sm", children: "Working on it..." }) }) })
|
|
8891
|
+
] }) }),
|
|
8892
|
+
/* @__PURE__ */ jsx(ConversationScrollButton, {})
|
|
8893
|
+
] }),
|
|
8894
|
+
/* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
|
|
8895
|
+
retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
8896
|
+
disabled && disabledReason ? /* @__PURE__ */ jsx(
|
|
8897
|
+
"div",
|
|
8097
8898
|
{
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
onKeyDown: (event) => {
|
|
8102
|
-
if (event.key === "Enter") runFind(event.shiftKey);
|
|
8103
|
-
},
|
|
8104
|
-
placeholder: "Find",
|
|
8105
|
-
"aria-label": "Find in PDF",
|
|
8106
|
-
className: "h-7 w-28 border-input px-1 text-xs"
|
|
8899
|
+
className: "rounded border border-line bg-muted/40 px-3 py-2 text-sm text-foreground/60",
|
|
8900
|
+
role: "status",
|
|
8901
|
+
children: disabledReason
|
|
8107
8902
|
}
|
|
8108
|
-
)
|
|
8109
|
-
|
|
8110
|
-
Button,
|
|
8903
|
+
) : /* @__PURE__ */ jsx(
|
|
8904
|
+
ChatComposer,
|
|
8111
8905
|
{
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8906
|
+
onSend,
|
|
8907
|
+
onStop,
|
|
8908
|
+
isRunning,
|
|
8909
|
+
disabled,
|
|
8910
|
+
disabledReason,
|
|
8911
|
+
tokenUsage,
|
|
8912
|
+
onComposerError,
|
|
8913
|
+
showBrowser,
|
|
8914
|
+
onToggleBrowser,
|
|
8915
|
+
showWorkspace,
|
|
8916
|
+
onToggleWorkspace,
|
|
8917
|
+
canShowBrowser,
|
|
8918
|
+
canShowWorkspace,
|
|
8919
|
+
viewMode,
|
|
8920
|
+
onViewModeChange
|
|
8118
8921
|
}
|
|
8119
8922
|
)
|
|
8120
|
-
] })
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8923
|
+
] })
|
|
8924
|
+
] });
|
|
8925
|
+
}
|
|
8926
|
+
var noop = () => {
|
|
8927
|
+
};
|
|
8928
|
+
var FileTreeContext = createContext({
|
|
8929
|
+
expandedPaths: /* @__PURE__ */ new Set(),
|
|
8930
|
+
togglePath: noop
|
|
8931
|
+
});
|
|
8932
|
+
function FileTree({
|
|
8933
|
+
expanded: controlledExpanded,
|
|
8934
|
+
defaultExpanded = /* @__PURE__ */ new Set(),
|
|
8935
|
+
selectedPath,
|
|
8936
|
+
onSelect,
|
|
8937
|
+
onExpandedChange,
|
|
8938
|
+
className,
|
|
8939
|
+
children,
|
|
8940
|
+
...props
|
|
8941
|
+
}) {
|
|
8942
|
+
const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
|
|
8943
|
+
const expandedPaths = controlledExpanded ?? internalExpanded;
|
|
8944
|
+
const togglePath = useCallback(
|
|
8945
|
+
(path) => {
|
|
8946
|
+
const next = new Set(expandedPaths);
|
|
8947
|
+
if (next.has(path)) {
|
|
8948
|
+
next.delete(path);
|
|
8949
|
+
} else {
|
|
8950
|
+
next.add(path);
|
|
8951
|
+
}
|
|
8952
|
+
setInternalExpanded(next);
|
|
8953
|
+
onExpandedChange?.(next);
|
|
8954
|
+
},
|
|
8955
|
+
[expandedPaths, onExpandedChange]
|
|
8956
|
+
);
|
|
8957
|
+
const contextValue = useMemo(
|
|
8958
|
+
() => ({
|
|
8959
|
+
expandedPaths,
|
|
8960
|
+
onSelect,
|
|
8961
|
+
selectedPath: selectedPath ?? void 0,
|
|
8962
|
+
togglePath
|
|
8963
|
+
}),
|
|
8964
|
+
[expandedPaths, onSelect, selectedPath, togglePath]
|
|
8965
|
+
);
|
|
8966
|
+
return /* @__PURE__ */ jsx(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
8967
|
+
"div",
|
|
8968
|
+
{
|
|
8969
|
+
className: cn("rounded-lg border bg-background text-sm", className),
|
|
8970
|
+
role: "tree",
|
|
8971
|
+
...props,
|
|
8972
|
+
children: /* @__PURE__ */ jsx("div", { className: "p-2", children })
|
|
8973
|
+
}
|
|
8974
|
+
) });
|
|
8975
|
+
}
|
|
8976
|
+
function FileTreeIcon({
|
|
8977
|
+
className,
|
|
8978
|
+
children,
|
|
8979
|
+
...props
|
|
8980
|
+
}) {
|
|
8981
|
+
return /* @__PURE__ */ jsx("span", { className: cn("shrink-0", className), ...props, children });
|
|
8982
|
+
}
|
|
8983
|
+
function FileTreeName({
|
|
8984
|
+
className,
|
|
8985
|
+
children,
|
|
8986
|
+
...props
|
|
8987
|
+
}) {
|
|
8988
|
+
return /* @__PURE__ */ jsx("span", { className: cn("truncate", className), ...props, children });
|
|
8989
|
+
}
|
|
8990
|
+
function FileTreeFolder({
|
|
8991
|
+
path,
|
|
8992
|
+
name,
|
|
8993
|
+
className,
|
|
8994
|
+
children,
|
|
8995
|
+
...props
|
|
8996
|
+
}) {
|
|
8997
|
+
const { expandedPaths, togglePath, selectedPath, onSelect } = useContext(FileTreeContext);
|
|
8998
|
+
const isExpanded = expandedPaths.has(path);
|
|
8999
|
+
const isSelected = selectedPath === path;
|
|
9000
|
+
const handleOpenChange = useCallback(() => {
|
|
9001
|
+
togglePath(path);
|
|
9002
|
+
}, [togglePath, path]);
|
|
9003
|
+
const handleSelect = useCallback(() => {
|
|
9004
|
+
onSelect?.(path);
|
|
9005
|
+
}, [onSelect, path]);
|
|
9006
|
+
return /* @__PURE__ */ jsx(Collapsible, { onOpenChange: handleOpenChange, open: isExpanded, children: /* @__PURE__ */ jsxs("div", { className: cn("", className), role: "treeitem", tabIndex: 0, ...props, children: [
|
|
9007
|
+
/* @__PURE__ */ jsxs(
|
|
8126
9008
|
"div",
|
|
8127
9009
|
{
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
9010
|
+
className: cn(
|
|
9011
|
+
"flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50",
|
|
9012
|
+
isSelected && "bg-muted"
|
|
9013
|
+
),
|
|
9014
|
+
children: [
|
|
9015
|
+
/* @__PURE__ */ jsx(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
9016
|
+
"button",
|
|
9017
|
+
{
|
|
9018
|
+
className: "flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0",
|
|
9019
|
+
type: "button",
|
|
9020
|
+
"aria-label": isExpanded ? `Collapse ${name}` : `Expand ${name}`,
|
|
9021
|
+
children: /* @__PURE__ */ jsx(
|
|
9022
|
+
ChevronRightIcon,
|
|
9023
|
+
{
|
|
9024
|
+
className: cn(
|
|
9025
|
+
"size-4 shrink-0 text-muted-foreground transition-transform",
|
|
9026
|
+
isExpanded && "rotate-90"
|
|
9027
|
+
)
|
|
9028
|
+
}
|
|
9029
|
+
)
|
|
9030
|
+
}
|
|
9031
|
+
) }),
|
|
9032
|
+
/* @__PURE__ */ jsxs(
|
|
9033
|
+
"button",
|
|
9034
|
+
{
|
|
9035
|
+
className: "flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left",
|
|
9036
|
+
onClick: handleSelect,
|
|
9037
|
+
type: "button",
|
|
9038
|
+
children: [
|
|
9039
|
+
/* @__PURE__ */ jsx(FileTreeIcon, { children: isExpanded ? /* @__PURE__ */ jsx(FolderOpenIcon, { className: "size-4 text-blue-500" }) : /* @__PURE__ */ jsx(FolderIcon, { className: "size-4 text-blue-500" }) }),
|
|
9040
|
+
/* @__PURE__ */ jsx(FileTreeName, { children: name })
|
|
9041
|
+
]
|
|
9042
|
+
}
|
|
9043
|
+
)
|
|
9044
|
+
]
|
|
8132
9045
|
}
|
|
8133
|
-
)
|
|
8134
|
-
|
|
8135
|
-
}
|
|
8136
|
-
function decodeBase64(content) {
|
|
8137
|
-
const binary = globalThis.atob(content);
|
|
8138
|
-
const bytes = new Uint8Array(binary.length);
|
|
8139
|
-
for (let index = 0; index < binary.length; index += 1) {
|
|
8140
|
-
bytes[index] = binary.charCodeAt(index);
|
|
8141
|
-
}
|
|
8142
|
-
return bytes;
|
|
9046
|
+
),
|
|
9047
|
+
/* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", { className: "ml-4 border-l border-muted-foreground/50 pl-2", children }) })
|
|
9048
|
+
] }) });
|
|
8143
9049
|
}
|
|
8144
|
-
function
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
9050
|
+
function FileTreeFile({
|
|
9051
|
+
path,
|
|
9052
|
+
name,
|
|
9053
|
+
icon,
|
|
9054
|
+
className,
|
|
9055
|
+
children,
|
|
9056
|
+
...props
|
|
9057
|
+
}) {
|
|
9058
|
+
const { selectedPath, onSelect } = useContext(FileTreeContext);
|
|
9059
|
+
const isSelected = selectedPath === path;
|
|
9060
|
+
const handleClick = useCallback(() => {
|
|
9061
|
+
onSelect?.(path);
|
|
9062
|
+
}, [onSelect, path]);
|
|
9063
|
+
const handleKeyDown = useCallback(
|
|
9064
|
+
(event) => {
|
|
9065
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
9066
|
+
onSelect?.(path);
|
|
9067
|
+
}
|
|
9068
|
+
},
|
|
9069
|
+
[onSelect, path]
|
|
9070
|
+
);
|
|
9071
|
+
return /* @__PURE__ */ jsx(
|
|
9072
|
+
"div",
|
|
9073
|
+
{
|
|
9074
|
+
className: cn(
|
|
9075
|
+
"group flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
|
|
9076
|
+
isSelected && "bg-muted",
|
|
9077
|
+
className
|
|
9078
|
+
),
|
|
9079
|
+
onClick: handleClick,
|
|
9080
|
+
onKeyDown: handleKeyDown,
|
|
9081
|
+
role: "treeitem",
|
|
9082
|
+
tabIndex: 0,
|
|
9083
|
+
...props,
|
|
9084
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9085
|
+
/* @__PURE__ */ jsx("span", { className: "size-4 shrink-0" }),
|
|
9086
|
+
/* @__PURE__ */ jsx(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsx(FileIcon, { className: "size-4 text-muted-foreground" }) }),
|
|
9087
|
+
/* @__PURE__ */ jsx(FileTreeName, { children: name })
|
|
9088
|
+
] })
|
|
9089
|
+
}
|
|
9090
|
+
);
|
|
8149
9091
|
}
|
|
8150
9092
|
var SKELETON_WIDTHS2 = [75, 60, 90, 65, 80, 70, 85, 55];
|
|
8151
9093
|
var DEFAULT_WIDTH = 400;
|
|
@@ -8574,7 +9516,7 @@ function WorkspacePanel({
|
|
|
8574
9516
|
}
|
|
8575
9517
|
),
|
|
8576
9518
|
/* @__PURE__ */ jsx(
|
|
8577
|
-
|
|
9519
|
+
ConfirmDialog2,
|
|
8578
9520
|
{
|
|
8579
9521
|
open: deleteTarget !== null,
|
|
8580
9522
|
title: "Delete file?",
|
|
@@ -8588,7 +9530,7 @@ function WorkspacePanel({
|
|
|
8588
9530
|
}
|
|
8589
9531
|
);
|
|
8590
9532
|
}
|
|
8591
|
-
function
|
|
9533
|
+
function ConfirmDialog2({
|
|
8592
9534
|
open,
|
|
8593
9535
|
title,
|
|
8594
9536
|
description,
|
|
@@ -8664,7 +9606,9 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
8664
9606
|
"skill.invoked",
|
|
8665
9607
|
"policy.denied",
|
|
8666
9608
|
"stream.timeout",
|
|
9609
|
+
"expert.delegation",
|
|
8667
9610
|
"expert.result",
|
|
9611
|
+
"expert.failure",
|
|
8668
9612
|
"expert.endorse",
|
|
8669
9613
|
"expert.override",
|
|
8670
9614
|
"user.feedback",
|
|
@@ -8674,7 +9618,9 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
8674
9618
|
"browser.destroyed",
|
|
8675
9619
|
"browser.control_granted",
|
|
8676
9620
|
"browser.control_returned",
|
|
8677
|
-
"
|
|
9621
|
+
"ask_user_question.response",
|
|
9622
|
+
"iteration.summary",
|
|
9623
|
+
"turn.summary"
|
|
8678
9624
|
];
|
|
8679
9625
|
|
|
8680
9626
|
// src/runtime/reducer.ts
|
|
@@ -8699,7 +9645,8 @@ function createInitialAgentChatState(options = {}) {
|
|
|
8699
9645
|
hadDeltas: false,
|
|
8700
9646
|
terminal: false,
|
|
8701
9647
|
workspaceRefreshKey: 0,
|
|
8702
|
-
browser: null
|
|
9648
|
+
browser: null,
|
|
9649
|
+
viewMode: options.viewMode ?? "simple"
|
|
8703
9650
|
};
|
|
8704
9651
|
}
|
|
8705
9652
|
function applyAgentChatEvent(state, event) {
|
|
@@ -8712,11 +9659,10 @@ function applyAgentChatEvent(state, event) {
|
|
|
8712
9659
|
nextState = applyRetryIndicator(nextState, event);
|
|
8713
9660
|
switch (event.type) {
|
|
8714
9661
|
case "user.message":
|
|
8715
|
-
return withMessages(
|
|
8716
|
-
nextState
|
|
8717
|
-
event.eventId,
|
|
8718
|
-
|
|
8719
|
-
));
|
|
9662
|
+
return withMessages(
|
|
9663
|
+
{ ...nextState, terminal: false, isRunning: true },
|
|
9664
|
+
applyUserMessage(nextState.messages, event.eventId, event.data)
|
|
9665
|
+
);
|
|
8720
9666
|
case "skill.invoked":
|
|
8721
9667
|
return withMessages(nextState, [
|
|
8722
9668
|
...nextState.messages,
|
|
@@ -8791,7 +9737,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
8791
9737
|
}
|
|
8792
9738
|
case "harness.wake":
|
|
8793
9739
|
case "llm.request":
|
|
8794
|
-
return
|
|
9740
|
+
return { ...nextState, terminal: false, isRunning: true };
|
|
8795
9741
|
case "harness.crash":
|
|
8796
9742
|
case "stream.timeout":
|
|
8797
9743
|
return nextState;
|
|
@@ -8815,10 +9761,17 @@ function applyAgentChatEvent(state, event) {
|
|
|
8815
9761
|
};
|
|
8816
9762
|
}
|
|
8817
9763
|
return nextState;
|
|
9764
|
+
case "expert.delegation":
|
|
9765
|
+
return applyExpertDelegation(nextState, event);
|
|
8818
9766
|
case "expert.result":
|
|
8819
9767
|
return withMessages(
|
|
8820
9768
|
nextState,
|
|
8821
|
-
applyExpertResult(nextState.messages, event.eventId)
|
|
9769
|
+
applyExpertResult(nextState.messages, event.eventId, event.data)
|
|
9770
|
+
);
|
|
9771
|
+
case "expert.failure":
|
|
9772
|
+
return withMessages(
|
|
9773
|
+
nextState,
|
|
9774
|
+
applyExpertFailure(nextState.messages, event.eventId, event.data)
|
|
8822
9775
|
);
|
|
8823
9776
|
case "expert.endorse":
|
|
8824
9777
|
case "expert.override":
|
|
@@ -8831,15 +9784,19 @@ function applyAgentChatEvent(state, event) {
|
|
|
8831
9784
|
nextState,
|
|
8832
9785
|
applyUserFeedback(nextState.messages, event.data)
|
|
8833
9786
|
);
|
|
8834
|
-
case "
|
|
9787
|
+
case "ask_user_question.response":
|
|
8835
9788
|
return withMessages(
|
|
8836
9789
|
nextState,
|
|
8837
|
-
|
|
9790
|
+
applyAskUserQuestionResponse(nextState.messages, event.data)
|
|
8838
9791
|
);
|
|
8839
9792
|
case "policy.denied":
|
|
8840
9793
|
return applyPolicyDenied(nextState, event.data);
|
|
8841
9794
|
case "session.start":
|
|
8842
9795
|
return nextState;
|
|
9796
|
+
case "iteration.summary":
|
|
9797
|
+
return applyIterationSummary(nextState, event);
|
|
9798
|
+
case "turn.summary":
|
|
9799
|
+
return applyTurnSummary(nextState, event);
|
|
8843
9800
|
}
|
|
8844
9801
|
}
|
|
8845
9802
|
function applyRetryIndicator(state, event) {
|
|
@@ -8972,6 +9929,7 @@ function browserMarker(event) {
|
|
|
8972
9929
|
function applyLlmDelta(state, event) {
|
|
8973
9930
|
const deltaContent = stringValue2(event.data.content);
|
|
8974
9931
|
const deltaReasoning = stringValue2(event.data.reasoning);
|
|
9932
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
8975
9933
|
const messages = [...state.messages];
|
|
8976
9934
|
const lastIdx = findLastAssistantIndex(messages);
|
|
8977
9935
|
const lastMsg = lastIdx >= 0 ? messages[lastIdx] : null;
|
|
@@ -8986,7 +9944,9 @@ function applyLlmDelta(state, event) {
|
|
|
8986
9944
|
messages[lastIdx] = {
|
|
8987
9945
|
...lastMsg,
|
|
8988
9946
|
content: deltaContent ? lastMsg.content + deltaContent : lastMsg.content,
|
|
8989
|
-
reasoning: deltaReasoning ? (lastMsg.reasoning ?? "") + deltaReasoning : lastMsg.reasoning
|
|
9947
|
+
reasoning: deltaReasoning ? (lastMsg.reasoning ?? "") + deltaReasoning : lastMsg.reasoning,
|
|
9948
|
+
turnId: turnId ?? lastMsg.turnId,
|
|
9949
|
+
iterationIndex: iterationIndex ?? lastMsg.iterationIndex
|
|
8990
9950
|
};
|
|
8991
9951
|
} else {
|
|
8992
9952
|
messages.push({
|
|
@@ -8995,14 +9955,17 @@ function applyLlmDelta(state, event) {
|
|
|
8995
9955
|
content: deltaContent,
|
|
8996
9956
|
reasoning: deltaReasoning || void 0,
|
|
8997
9957
|
createdAt: /* @__PURE__ */ new Date(),
|
|
8998
|
-
status: "streaming"
|
|
9958
|
+
status: "streaming",
|
|
9959
|
+
turnId,
|
|
9960
|
+
iterationIndex
|
|
8999
9961
|
});
|
|
9000
9962
|
}
|
|
9001
9963
|
return {
|
|
9002
9964
|
...state,
|
|
9003
9965
|
messages,
|
|
9004
9966
|
hadDeltas: state.hadDeltas || Boolean(deltaContent),
|
|
9005
|
-
|
|
9967
|
+
terminal: false,
|
|
9968
|
+
isRunning: true
|
|
9006
9969
|
};
|
|
9007
9970
|
}
|
|
9008
9971
|
function applyLlmResponse(state, event) {
|
|
@@ -9012,6 +9975,7 @@ function applyLlmResponse(state, event) {
|
|
|
9012
9975
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
9013
9976
|
const hasToolCalls = toolCalls.length > 0;
|
|
9014
9977
|
const responseToolCallIds = toolCallIdsFromResponse(toolCalls);
|
|
9978
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
9015
9979
|
const idx = findLastAssistantIndex(messages);
|
|
9016
9980
|
const prevAssistant = idx >= 0 ? messages[idx] : void 0;
|
|
9017
9981
|
const prevHasTools = Boolean(prevAssistant?.toolCalls?.length);
|
|
@@ -9029,13 +9993,17 @@ function applyLlmResponse(state, event) {
|
|
|
9029
9993
|
reasoning: (current.reasoning ?? "") + current.content,
|
|
9030
9994
|
content: "",
|
|
9031
9995
|
status: "streaming",
|
|
9032
|
-
llmResponseEventId: event.eventId
|
|
9996
|
+
llmResponseEventId: event.eventId,
|
|
9997
|
+
turnId: turnId ?? current.turnId,
|
|
9998
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9033
9999
|
};
|
|
9034
10000
|
} else {
|
|
9035
10001
|
messages[idx] = {
|
|
9036
10002
|
...current,
|
|
9037
10003
|
status: "complete",
|
|
9038
|
-
llmResponseEventId: event.eventId
|
|
10004
|
+
llmResponseEventId: event.eventId,
|
|
10005
|
+
turnId: turnId ?? current.turnId,
|
|
10006
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9039
10007
|
};
|
|
9040
10008
|
}
|
|
9041
10009
|
} else if (matchesExistingToolTurn && idx >= 0) {
|
|
@@ -9044,7 +10012,9 @@ function applyLlmResponse(state, event) {
|
|
|
9044
10012
|
...current,
|
|
9045
10013
|
reasoning: responseContent ? appendText(current.reasoning, responseContent) : current.reasoning,
|
|
9046
10014
|
status: "streaming",
|
|
9047
|
-
llmResponseEventId: event.eventId
|
|
10015
|
+
llmResponseEventId: event.eventId,
|
|
10016
|
+
turnId: turnId ?? current.turnId,
|
|
10017
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9048
10018
|
};
|
|
9049
10019
|
} else if (prevHasTools || !prevAssistant || hasUserAfter) {
|
|
9050
10020
|
messages.push({
|
|
@@ -9054,7 +10024,9 @@ function applyLlmResponse(state, event) {
|
|
|
9054
10024
|
reasoning: hasToolCalls && responseContent ? responseContent : void 0,
|
|
9055
10025
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9056
10026
|
status: hasToolCalls ? "streaming" : "complete",
|
|
9057
|
-
llmResponseEventId: event.eventId
|
|
10027
|
+
llmResponseEventId: event.eventId,
|
|
10028
|
+
turnId,
|
|
10029
|
+
iterationIndex
|
|
9058
10030
|
});
|
|
9059
10031
|
} else {
|
|
9060
10032
|
const current = messages[idx];
|
|
@@ -9063,14 +10035,18 @@ function applyLlmResponse(state, event) {
|
|
|
9063
10035
|
...current,
|
|
9064
10036
|
reasoning: (current.reasoning ?? "") + responseContent,
|
|
9065
10037
|
status: "streaming",
|
|
9066
|
-
llmResponseEventId: event.eventId
|
|
10038
|
+
llmResponseEventId: event.eventId,
|
|
10039
|
+
turnId: turnId ?? current.turnId,
|
|
10040
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9067
10041
|
};
|
|
9068
10042
|
} else {
|
|
9069
10043
|
messages[idx] = {
|
|
9070
10044
|
...current,
|
|
9071
10045
|
content: responseContent || current.content,
|
|
9072
10046
|
status: hasToolCalls ? "streaming" : "complete",
|
|
9073
|
-
llmResponseEventId: event.eventId
|
|
10047
|
+
llmResponseEventId: event.eventId,
|
|
10048
|
+
turnId: turnId ?? current.turnId,
|
|
10049
|
+
iterationIndex: iterationIndex ?? current.iterationIndex
|
|
9074
10050
|
};
|
|
9075
10051
|
}
|
|
9076
10052
|
}
|
|
@@ -9103,6 +10079,7 @@ ${addition}`;
|
|
|
9103
10079
|
}
|
|
9104
10080
|
function applyLlmThinking(state, event) {
|
|
9105
10081
|
const reasoningText = stringValue2(event.data.reasoning) || stringValue2(event.data.content);
|
|
10082
|
+
const { turnId, iterationIndex } = readTurnMeta(event.data);
|
|
9106
10083
|
const messages = [...state.messages];
|
|
9107
10084
|
const idx = findLastAssistantIndex(messages);
|
|
9108
10085
|
const prev = idx >= 0 ? messages[idx] : null;
|
|
@@ -9117,19 +10094,85 @@ function applyLlmThinking(state, event) {
|
|
|
9117
10094
|
content: "",
|
|
9118
10095
|
reasoning: reasoningText,
|
|
9119
10096
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9120
|
-
status: "streaming"
|
|
10097
|
+
status: "streaming",
|
|
10098
|
+
turnId,
|
|
10099
|
+
iterationIndex
|
|
9121
10100
|
});
|
|
9122
10101
|
} else {
|
|
9123
10102
|
messages[idx] = {
|
|
9124
10103
|
...prev,
|
|
9125
|
-
reasoning: (prev.reasoning ?? "") + reasoningText
|
|
10104
|
+
reasoning: (prev.reasoning ?? "") + reasoningText,
|
|
10105
|
+
turnId: turnId ?? prev.turnId,
|
|
10106
|
+
iterationIndex: iterationIndex ?? prev.iterationIndex
|
|
9126
10107
|
};
|
|
9127
10108
|
}
|
|
9128
10109
|
return {
|
|
9129
10110
|
...state,
|
|
9130
10111
|
messages,
|
|
9131
|
-
|
|
10112
|
+
terminal: false,
|
|
10113
|
+
isRunning: true
|
|
10114
|
+
};
|
|
10115
|
+
}
|
|
10116
|
+
function applyIterationSummary(state, event) {
|
|
10117
|
+
const turnId = optionalStringValue(event.data.turn_id);
|
|
10118
|
+
const iterationIndex = optionalNumberValue(event.data.iteration_index);
|
|
10119
|
+
const summary = optionalStringValue(event.data.summary);
|
|
10120
|
+
if (!turnId || iterationIndex === null || !summary) return state;
|
|
10121
|
+
const idx = state.messages.findIndex(
|
|
10122
|
+
(m) => m.role === "assistant" && m.turnId === turnId && m.iterationIndex === iterationIndex
|
|
10123
|
+
);
|
|
10124
|
+
if (idx < 0) return state;
|
|
10125
|
+
const toolCallIds = Array.isArray(event.data.tool_call_ids) ? event.data.tool_call_ids.map((x) => String(x)) : [];
|
|
10126
|
+
const messages = [...state.messages];
|
|
10127
|
+
messages[idx] = {
|
|
10128
|
+
...messages[idx],
|
|
10129
|
+
iterationSummary: {
|
|
10130
|
+
iterationIndex,
|
|
10131
|
+
summary,
|
|
10132
|
+
toolCallIds,
|
|
10133
|
+
startedAt: stringValue2(event.data.started_at),
|
|
10134
|
+
endedAt: stringValue2(event.data.ended_at)
|
|
10135
|
+
}
|
|
10136
|
+
};
|
|
10137
|
+
return { ...state, messages };
|
|
10138
|
+
}
|
|
10139
|
+
function applyTurnSummary(state, event) {
|
|
10140
|
+
const turnId = optionalStringValue(event.data.turn_id);
|
|
10141
|
+
if (!turnId) return state;
|
|
10142
|
+
const recap = stringValue2(event.data.recap);
|
|
10143
|
+
const artifacts = parseTurnArtifacts(event.data.artifacts);
|
|
10144
|
+
let idx = -1;
|
|
10145
|
+
for (let i = state.messages.length - 1; i >= 0; i--) {
|
|
10146
|
+
const message = state.messages[i];
|
|
10147
|
+
if (message.role === "assistant" && message.turnId === turnId) {
|
|
10148
|
+
idx = i;
|
|
10149
|
+
break;
|
|
10150
|
+
}
|
|
10151
|
+
}
|
|
10152
|
+
if (idx < 0) return state;
|
|
10153
|
+
const messages = [...state.messages];
|
|
10154
|
+
messages[idx] = {
|
|
10155
|
+
...messages[idx],
|
|
10156
|
+
turnSummary: { turnId, recap, artifacts }
|
|
9132
10157
|
};
|
|
10158
|
+
return { ...state, messages };
|
|
10159
|
+
}
|
|
10160
|
+
function parseTurnArtifacts(raw) {
|
|
10161
|
+
if (!Array.isArray(raw)) return [];
|
|
10162
|
+
const out = [];
|
|
10163
|
+
for (const item of raw) {
|
|
10164
|
+
if (!item || typeof item !== "object") continue;
|
|
10165
|
+
const obj = item;
|
|
10166
|
+
const kind = obj.kind;
|
|
10167
|
+
if (kind !== "file" && kind !== "artifact" && kind !== "url" && kind !== "command") {
|
|
10168
|
+
continue;
|
|
10169
|
+
}
|
|
10170
|
+
const label = typeof obj.label === "string" ? obj.label : "";
|
|
10171
|
+
const ref = typeof obj.ref === "string" ? obj.ref : "";
|
|
10172
|
+
if (!label || !ref) continue;
|
|
10173
|
+
out.push({ kind, label, ref });
|
|
10174
|
+
}
|
|
10175
|
+
return out;
|
|
9133
10176
|
}
|
|
9134
10177
|
function applyToolCall(state, event) {
|
|
9135
10178
|
const messages = [...state.messages];
|
|
@@ -9166,7 +10209,8 @@ function applyToolCall(state, event) {
|
|
|
9166
10209
|
return {
|
|
9167
10210
|
...state,
|
|
9168
10211
|
messages,
|
|
9169
|
-
|
|
10212
|
+
terminal: false,
|
|
10213
|
+
isRunning: true
|
|
9170
10214
|
};
|
|
9171
10215
|
}
|
|
9172
10216
|
function applyToolResult(messages, data) {
|
|
@@ -9244,16 +10288,84 @@ function buildErrorInfo(event) {
|
|
|
9244
10288
|
retryable: Boolean(event.data.retryable)
|
|
9245
10289
|
};
|
|
9246
10290
|
}
|
|
9247
|
-
function applyExpertResult(messages, eventId) {
|
|
10291
|
+
function applyExpertResult(messages, eventId, data) {
|
|
9248
10292
|
const match = findLatestConsultExpertCall(messages);
|
|
9249
10293
|
if (!match) return messages;
|
|
10294
|
+
const content = stringValue2(data.content);
|
|
9250
10295
|
const next = [...messages];
|
|
9251
10296
|
const msg = next[match.msgIdx];
|
|
9252
10297
|
next[match.msgIdx] = {
|
|
9253
10298
|
...msg,
|
|
9254
|
-
toolCalls: msg.toolCalls?.map(
|
|
9255
|
-
(tc
|
|
9256
|
-
|
|
10299
|
+
toolCalls: msg.toolCalls?.map((tc) => {
|
|
10300
|
+
if (tc.id !== match.toolId) return tc;
|
|
10301
|
+
const updated = {
|
|
10302
|
+
...tc,
|
|
10303
|
+
expertResultEventId: eventId,
|
|
10304
|
+
status: "complete"
|
|
10305
|
+
};
|
|
10306
|
+
if (tc.result === void 0 && content) {
|
|
10307
|
+
updated.result = JSON.stringify({ content });
|
|
10308
|
+
}
|
|
10309
|
+
return updated;
|
|
10310
|
+
})
|
|
10311
|
+
};
|
|
10312
|
+
return next;
|
|
10313
|
+
}
|
|
10314
|
+
function applyExpertDelegation(state, event) {
|
|
10315
|
+
if (findLatestConsultExpertCall(state.messages) !== null) {
|
|
10316
|
+
return state;
|
|
10317
|
+
}
|
|
10318
|
+
const expertName = stringValue2(event.data.expert);
|
|
10319
|
+
const task = stringValue2(event.data.task);
|
|
10320
|
+
if (!expertName) return state;
|
|
10321
|
+
const messages = [...state.messages];
|
|
10322
|
+
const assistantIdx = findLastAssistantIndex(messages);
|
|
10323
|
+
let assistant = assistantIdx >= 0 ? messages[assistantIdx] : null;
|
|
10324
|
+
const userAfterAssistant = assistantIdx >= 0 && hasUserAfterIndex(messages, assistantIdx);
|
|
10325
|
+
if (!assistant || assistant.status === "complete" || userAfterAssistant) {
|
|
10326
|
+
assistant = {
|
|
10327
|
+
id: `evt-${event.eventId}-expert-delegation`,
|
|
10328
|
+
role: "assistant",
|
|
10329
|
+
content: "",
|
|
10330
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
10331
|
+
status: "streaming"
|
|
10332
|
+
};
|
|
10333
|
+
messages.push(assistant);
|
|
10334
|
+
} else {
|
|
10335
|
+
assistant = { ...assistant };
|
|
10336
|
+
messages[assistantIdx] = assistant;
|
|
10337
|
+
}
|
|
10338
|
+
const toolCall = {
|
|
10339
|
+
id: `expert-delegation-${event.eventId}`,
|
|
10340
|
+
toolName: "consult_expert",
|
|
10341
|
+
args: JSON.stringify({ expert: expertName, question: task }),
|
|
10342
|
+
status: "running"
|
|
10343
|
+
};
|
|
10344
|
+
assistant.toolCalls = [...assistant.toolCalls ?? [], toolCall];
|
|
10345
|
+
return {
|
|
10346
|
+
...state,
|
|
10347
|
+
messages,
|
|
10348
|
+
terminal: false,
|
|
10349
|
+
isRunning: true
|
|
10350
|
+
};
|
|
10351
|
+
}
|
|
10352
|
+
function applyExpertFailure(messages, eventId, data) {
|
|
10353
|
+
const match = findLatestConsultExpertCall(messages);
|
|
10354
|
+
if (!match) return messages;
|
|
10355
|
+
const errorMsg = stringValue2(data.error) || "Expert consultation failed.";
|
|
10356
|
+
const next = [...messages];
|
|
10357
|
+
const msg = next[match.msgIdx];
|
|
10358
|
+
next[match.msgIdx] = {
|
|
10359
|
+
...msg,
|
|
10360
|
+
toolCalls: msg.toolCalls?.map((tc) => {
|
|
10361
|
+
if (tc.id !== match.toolId) return tc;
|
|
10362
|
+
return {
|
|
10363
|
+
...tc,
|
|
10364
|
+
expertResultEventId: eventId,
|
|
10365
|
+
status: "error",
|
|
10366
|
+
result: tc.result ?? JSON.stringify({ error: errorMsg })
|
|
10367
|
+
};
|
|
10368
|
+
})
|
|
9257
10369
|
};
|
|
9258
10370
|
return next;
|
|
9259
10371
|
}
|
|
@@ -9303,7 +10415,7 @@ function applyUserFeedback(messages, data) {
|
|
|
9303
10415
|
}
|
|
9304
10416
|
return messages;
|
|
9305
10417
|
}
|
|
9306
|
-
function
|
|
10418
|
+
function applyAskUserQuestionResponse(messages, data) {
|
|
9307
10419
|
const targetToolId = stringValue2(data.tool_call_id);
|
|
9308
10420
|
const responses = Array.isArray(data.responses) ? data.responses : void 0;
|
|
9309
10421
|
if (!targetToolId || !responses) return messages;
|
|
@@ -9316,7 +10428,7 @@ function applyClarifyResponse(messages, data) {
|
|
|
9316
10428
|
toolCalls: msg.toolCalls.map(
|
|
9317
10429
|
(tc) => tc.id === targetToolId ? {
|
|
9318
10430
|
...tc,
|
|
9319
|
-
|
|
10431
|
+
askUserQuestionAnswers: responses.map((response) => {
|
|
9320
10432
|
const row = objectValue(response) ?? {};
|
|
9321
10433
|
return {
|
|
9322
10434
|
question: stringValue2(row.question),
|
|
@@ -9398,8 +10510,39 @@ function stringValue2(value) {
|
|
|
9398
10510
|
function numberValue(value) {
|
|
9399
10511
|
return typeof value === "number" ? value : 0;
|
|
9400
10512
|
}
|
|
10513
|
+
function optionalNumberValue(value) {
|
|
10514
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
10515
|
+
}
|
|
10516
|
+
function optionalStringValue(value) {
|
|
10517
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
10518
|
+
}
|
|
10519
|
+
function readTurnMeta(data) {
|
|
10520
|
+
const turnId = optionalStringValue(data.turn_id);
|
|
10521
|
+
const iterationIndex = optionalNumberValue(data.iteration_index);
|
|
10522
|
+
return {
|
|
10523
|
+
turnId,
|
|
10524
|
+
iterationIndex: iterationIndex === null ? void 0 : iterationIndex
|
|
10525
|
+
};
|
|
10526
|
+
}
|
|
9401
10527
|
|
|
9402
10528
|
// src/runtime/use-agent-chat-runtime.ts
|
|
10529
|
+
var VIEW_MODE_KEY = "@invergent/agent-chat-react:viewMode";
|
|
10530
|
+
function readPersistedViewMode() {
|
|
10531
|
+
if (typeof window === "undefined") return null;
|
|
10532
|
+
try {
|
|
10533
|
+
const raw = window.localStorage.getItem(VIEW_MODE_KEY);
|
|
10534
|
+
if (raw === "simple" || raw === "expert") return raw;
|
|
10535
|
+
} catch {
|
|
10536
|
+
}
|
|
10537
|
+
return null;
|
|
10538
|
+
}
|
|
10539
|
+
function writePersistedViewMode(mode) {
|
|
10540
|
+
if (typeof window === "undefined") return;
|
|
10541
|
+
try {
|
|
10542
|
+
window.localStorage.setItem(VIEW_MODE_KEY, mode);
|
|
10543
|
+
} catch {
|
|
10544
|
+
}
|
|
10545
|
+
}
|
|
9403
10546
|
function useAgentChatRuntime({
|
|
9404
10547
|
adapter,
|
|
9405
10548
|
agentId,
|
|
@@ -9407,7 +10550,13 @@ function useAgentChatRuntime({
|
|
|
9407
10550
|
onSessionChange
|
|
9408
10551
|
}) {
|
|
9409
10552
|
const [state, setState] = useState(
|
|
9410
|
-
() => createInitialAgentChatState({
|
|
10553
|
+
() => createInitialAgentChatState({
|
|
10554
|
+
isLoadingHistory: Boolean(sessionId),
|
|
10555
|
+
// Seed from localStorage so the first paint matches the user's
|
|
10556
|
+
// last choice without flashing the default. The async adapter
|
|
10557
|
+
// load can still upgrade this later.
|
|
10558
|
+
viewMode: readPersistedViewMode() ?? "simple"
|
|
10559
|
+
})
|
|
9411
10560
|
);
|
|
9412
10561
|
const [session, setSession] = useState(null);
|
|
9413
10562
|
const stateRef = useRef(state);
|
|
@@ -9703,6 +10852,41 @@ function useAgentChatRuntime({
|
|
|
9703
10852
|
throw error;
|
|
9704
10853
|
}
|
|
9705
10854
|
}, [adapter, sessionId]);
|
|
10855
|
+
useEffect(() => {
|
|
10856
|
+
if (!adapter.getChatViewMode) {
|
|
10857
|
+
const cached = readPersistedViewMode();
|
|
10858
|
+
if (cached !== null) {
|
|
10859
|
+
setState(
|
|
10860
|
+
(prev) => prev.viewMode === cached ? prev : { ...prev, viewMode: cached }
|
|
10861
|
+
);
|
|
10862
|
+
}
|
|
10863
|
+
return;
|
|
10864
|
+
}
|
|
10865
|
+
let cancelled = false;
|
|
10866
|
+
void adapter.getChatViewMode().then((persisted) => {
|
|
10867
|
+
if (cancelled) return;
|
|
10868
|
+
if (persisted === "simple" || persisted === "expert") {
|
|
10869
|
+
setState(
|
|
10870
|
+
(prev) => prev.viewMode === persisted ? prev : { ...prev, viewMode: persisted }
|
|
10871
|
+
);
|
|
10872
|
+
}
|
|
10873
|
+
}).catch(() => void 0);
|
|
10874
|
+
return () => {
|
|
10875
|
+
cancelled = true;
|
|
10876
|
+
};
|
|
10877
|
+
}, [adapter]);
|
|
10878
|
+
const setViewMode = useCallback(
|
|
10879
|
+
(mode) => {
|
|
10880
|
+
setState(
|
|
10881
|
+
(prev) => prev.viewMode === mode ? prev : { ...prev, viewMode: mode }
|
|
10882
|
+
);
|
|
10883
|
+
writePersistedViewMode(mode);
|
|
10884
|
+
if (adapter.setChatViewMode) {
|
|
10885
|
+
void adapter.setChatViewMode(mode).catch(() => void 0);
|
|
10886
|
+
}
|
|
10887
|
+
},
|
|
10888
|
+
[adapter]
|
|
10889
|
+
);
|
|
9706
10890
|
return {
|
|
9707
10891
|
state,
|
|
9708
10892
|
session,
|
|
@@ -9716,7 +10900,9 @@ function useAgentChatRuntime({
|
|
|
9716
10900
|
stop,
|
|
9717
10901
|
retry,
|
|
9718
10902
|
markSending,
|
|
9719
|
-
markSendError
|
|
10903
|
+
markSendError,
|
|
10904
|
+
viewMode: state.viewMode,
|
|
10905
|
+
setViewMode
|
|
9720
10906
|
};
|
|
9721
10907
|
}
|
|
9722
10908
|
function parseEventData(data) {
|
|
@@ -9787,6 +10973,9 @@ function AgentChat({
|
|
|
9787
10973
|
sessionId,
|
|
9788
10974
|
onSessionChange
|
|
9789
10975
|
});
|
|
10976
|
+
useEffect(() => {
|
|
10977
|
+
setShowWorkspace(runtime.viewMode === "expert");
|
|
10978
|
+
}, [runtime.viewMode]);
|
|
9790
10979
|
const isReadOnlySession = isScheduledRunSession(runtime.session);
|
|
9791
10980
|
const effectiveDisabled = disabled || isReadOnlySession;
|
|
9792
10981
|
const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
|
|
@@ -9907,7 +11096,9 @@ function AgentChat({
|
|
|
9907
11096
|
showWorkspace,
|
|
9908
11097
|
onToggleWorkspace: handleToggleWorkspace,
|
|
9909
11098
|
canShowBrowser: browserAvailable,
|
|
9910
|
-
canShowWorkspace: workspaceAvailable
|
|
11099
|
+
canShowWorkspace: workspaceAvailable,
|
|
11100
|
+
viewMode: runtime.viewMode,
|
|
11101
|
+
onViewModeChange: runtime.setViewMode
|
|
9911
11102
|
}
|
|
9912
11103
|
)
|
|
9913
11104
|
}
|
|
@@ -9943,7 +11134,8 @@ function AgentChat({
|
|
|
9943
11134
|
{
|
|
9944
11135
|
sessionId,
|
|
9945
11136
|
state: browserState,
|
|
9946
|
-
adapter
|
|
11137
|
+
adapter,
|
|
11138
|
+
onClose: () => setShowBrowser(false)
|
|
9947
11139
|
}
|
|
9948
11140
|
)
|
|
9949
11141
|
}
|
|
@@ -10127,7 +11319,7 @@ function InputRequiredDetail({
|
|
|
10127
11319
|
answer: answers[question.prompt]?.trim() ?? "",
|
|
10128
11320
|
is_other: false
|
|
10129
11321
|
}));
|
|
10130
|
-
await adapter.
|
|
11322
|
+
await adapter.submitAskUserQuestionResponse({
|
|
10131
11323
|
sessionId: item.sessionId,
|
|
10132
11324
|
toolCallId,
|
|
10133
11325
|
responses
|
|
@@ -10711,7 +11903,7 @@ function groupMissionTasksByBucket(tasks) {
|
|
|
10711
11903
|
function deriveMissionWorkerActivityLabel(worker) {
|
|
10712
11904
|
const kind = worker.latestEventKind;
|
|
10713
11905
|
if (kind === "tool.call" && worker.latestEventSummary) {
|
|
10714
|
-
return `tool: ${
|
|
11906
|
+
return `tool: ${truncate3(worker.latestEventSummary, 80)}`;
|
|
10715
11907
|
}
|
|
10716
11908
|
if (kind === "llm.response") {
|
|
10717
11909
|
return "thinking";
|
|
@@ -10720,11 +11912,11 @@ function deriveMissionWorkerActivityLabel(worker) {
|
|
|
10720
11912
|
return "received tool result";
|
|
10721
11913
|
}
|
|
10722
11914
|
if (kind && worker.latestEventSummary) {
|
|
10723
|
-
return `${kind}: ${
|
|
11915
|
+
return `${kind}: ${truncate3(worker.latestEventSummary, 60)}`;
|
|
10724
11916
|
}
|
|
10725
11917
|
return worker.sessionStatus || "active";
|
|
10726
11918
|
}
|
|
10727
|
-
function
|
|
11919
|
+
function truncate3(s, max) {
|
|
10728
11920
|
if (s.length <= max) return s;
|
|
10729
11921
|
return `${s.slice(0, max - 1)}\u2026`;
|
|
10730
11922
|
}
|
|
@@ -12092,7 +13284,8 @@ function pruneDeletedSessionNodes(nodes, deletedSessionId) {
|
|
|
12092
13284
|
return nodes.filter((node) => !deletedIds.has(node.id));
|
|
12093
13285
|
}
|
|
12094
13286
|
function formatSessionTime(value) {
|
|
12095
|
-
const
|
|
13287
|
+
const normalized = /[zZ]|[+-]\d{2}:?\d{2}$/.test(value) ? value : `${value}Z`;
|
|
13288
|
+
const date = new Date(normalized);
|
|
12096
13289
|
if (Number.isNaN(date.getTime())) return "";
|
|
12097
13290
|
return formatDistanceToNow(date, { addSuffix: true });
|
|
12098
13291
|
}
|
|
@@ -12132,7 +13325,6 @@ function TreeNodeRow({
|
|
|
12132
13325
|
const title = entry.title ?? fallbackSessionTitle(entry);
|
|
12133
13326
|
const subtitle = [
|
|
12134
13327
|
formatRunKind(entry.runKind),
|
|
12135
|
-
entry.model ?? entry.agentType,
|
|
12136
13328
|
formatSessionTime(entry.updatedAt)
|
|
12137
13329
|
].filter(Boolean).join(" \xB7 ");
|
|
12138
13330
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -12148,7 +13340,7 @@ function TreeNodeRow({
|
|
|
12148
13340
|
className: cn(
|
|
12149
13341
|
"group flex items-center gap-2 w-full py-2 pr-2 text-left cursor-pointer transition-colors border-l-2",
|
|
12150
13342
|
"min-h-11 md:min-h-0",
|
|
12151
|
-
isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-
|
|
13343
|
+
isActive ? "bg-line text-foreground border-l-primary" : "bg-transparent text-foreground/80 hover:bg-input hover:text-foreground border-l-transparent"
|
|
12152
13344
|
),
|
|
12153
13345
|
style: { paddingLeft: `${depth * 12 + 12}px` },
|
|
12154
13346
|
children: [
|