@invergent/agent-chat-react 2.16.8 → 2.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1225 -429
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +249 -6
- package/dist/index.d.ts +249 -6
- package/dist/index.js +1225 -434
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { cn, __publicField } from './chunk-47MF6JUW.js';
|
|
2
2
|
import { createContext, memo, useRef, useEffect, useCallback, useMemo, useState, useLayoutEffect, forwardRef, useId, lazy, useContext, useSyncExternalStore, Fragment as Fragment$1, Suspense, Children } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight as ChevronRight$1, RefreshCw, CreditCard, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, Pen, Eraser, Type, MousePointer2, Hand, Maximize2, Undo2, Redo2, CheckIcon, CopyIcon, DownloadIcon, Maximize2Icon, GlobeIcon, FolderIcon, MessageSquareIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, ChevronLeftIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, TrashIcon, ImageIcon, FileTextIcon, Clock, ArrowRight, ListTreeIcon, PenLineIcon, TerminalIcon, SparklesIcon, ClockIcon, PaperclipIcon, CloudIcon, HardDriveIcon, IdCardIcon, PlusIcon, ShrinkIcon, FolderOpenIcon, FileIcon, MinusIcon, SearchIcon, CircleDot, XCircle, CheckCircle2, ZapIcon, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, LibraryIcon, ListTodoIcon, BotIcon, ListIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
|
|
4
|
+
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight as ChevronRight$1, RefreshCw, CreditCard, File as File$1, FileImage, FileAudio, FileVideo, FileText, FileCode, FileArchive, FileSpreadsheet, PlugZapIcon, ChevronRightIcon, ArrowLeftIcon, Loader2Icon, InboxIcon, Loader2, AlertCircle, Pause, Play, Ban, TargetIcon, CalendarClockIcon, UsersIcon, Pen, Eraser, Type, MousePointer2, Hand, Maximize2, Undo2, Redo2, CheckIcon, CopyIcon, DownloadIcon, Maximize2Icon, LaptopIcon, GlobeIcon, FolderIcon, MessageSquareIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, ExternalLinkIcon, ClipboardCheckIcon, ShieldAlertIcon, TimerIcon, CircleDotIcon, ChevronLeftIcon, XIcon, Trash2Icon, SquareIcon, ArrowDownIcon, TrashIcon, ImageIcon, FileTextIcon, Clock, ArrowRight, ListTreeIcon, PenLineIcon, TerminalIcon, SparklesIcon, ClockIcon, PaperclipIcon, CloudIcon, HardDriveIcon, IdCardIcon, PlusIcon, ShrinkIcon, FolderOpenIcon, FileIcon, MinusIcon, SearchIcon, CircleDot, XCircle, CheckCircle2, ZapIcon, ArrowUpIcon, CircleCheckIcon, ThumbsUpIcon, ThumbsDownIcon, BookOpenIcon, GitBranchIcon, ActivityIcon, EyeIcon, LibraryIcon, ListTodoIcon, BotIcon, ListIcon, FileEditIcon, WrenchIcon, FileCodeIcon, CodeIcon, FileArchiveIcon, FileVideoIcon, FileAudioIcon, FileImageIcon, FileChartLineIcon, FileSpreadsheetIcon, XCircleIcon, CheckCircle2Icon, Code, CircleXIcon, SkullIcon, CheckCircleIcon, CircleIcon } from 'lucide-react';
|
|
5
5
|
import { cva } from 'class-variance-authority';
|
|
6
|
-
import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Checkbox as Checkbox$1, Label as Label$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
|
+
import { Collapsible as Collapsible$1, Slot, Tooltip as Tooltip$1, Checkbox as Checkbox$1, Label as Label$1, Progress as Progress$1, Tabs as Tabs$1, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1 } from 'radix-ui';
|
|
7
7
|
import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
|
|
8
8
|
import { cjk } from '@streamdown/cjk';
|
|
9
9
|
import { code } from '@streamdown/code';
|
|
@@ -32,6 +32,70 @@ function useAgentChatAdapterContext() {
|
|
|
32
32
|
}
|
|
33
33
|
return value;
|
|
34
34
|
}
|
|
35
|
+
function useProjectThreads(adapter, projectId) {
|
|
36
|
+
const [rows, setRows] = useState({});
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
setRows({});
|
|
39
|
+
if (!projectId || !adapter.listProjectThreads || !adapter.openProjectStream) return;
|
|
40
|
+
let closed = false;
|
|
41
|
+
let reading = false;
|
|
42
|
+
let wanted = /* @__PURE__ */ new Set();
|
|
43
|
+
const failed = /* @__PURE__ */ new Set();
|
|
44
|
+
const readOne = async (threadId) => {
|
|
45
|
+
if (threadId === null) {
|
|
46
|
+
const all = await adapter.listProjectThreads({ projectId });
|
|
47
|
+
if (!closed) setRows(Object.fromEntries(all.map((row2) => [row2.id, row2])));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const [row] = await adapter.listProjectThreads({ projectId, threadId });
|
|
51
|
+
if (!closed) setRows(({ [threadId]: _gone, ...rest }) => row ? { ...rest, [threadId]: row } : rest);
|
|
52
|
+
};
|
|
53
|
+
const read = async () => {
|
|
54
|
+
if (reading) return;
|
|
55
|
+
reading = true;
|
|
56
|
+
while (wanted.size > 0 && !closed) {
|
|
57
|
+
const asked = wanted;
|
|
58
|
+
wanted = /* @__PURE__ */ new Set();
|
|
59
|
+
for (const threadId of asked.has(null) ? [null] : asked) {
|
|
60
|
+
if (closed) break;
|
|
61
|
+
try {
|
|
62
|
+
await readOne(threadId);
|
|
63
|
+
} catch {
|
|
64
|
+
failed.add(threadId);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
reading = false;
|
|
69
|
+
};
|
|
70
|
+
const want = (threadId) => {
|
|
71
|
+
wanted.add(threadId);
|
|
72
|
+
for (const again of failed) wanted.add(again);
|
|
73
|
+
failed.clear();
|
|
74
|
+
void read();
|
|
75
|
+
};
|
|
76
|
+
const stream = adapter.openProjectStream({ projectId });
|
|
77
|
+
stream.onerror = () => {
|
|
78
|
+
if (closed) return;
|
|
79
|
+
closed = true;
|
|
80
|
+
setRows({});
|
|
81
|
+
};
|
|
82
|
+
stream.addEventListener("ready", () => want(null));
|
|
83
|
+
stream.addEventListener("change", (event) => {
|
|
84
|
+
let threadId = null;
|
|
85
|
+
try {
|
|
86
|
+
const named2 = JSON.parse(event.data).thread_id;
|
|
87
|
+
threadId = typeof named2 === "string" ? named2 : null;
|
|
88
|
+
} catch {
|
|
89
|
+
}
|
|
90
|
+
want(threadId);
|
|
91
|
+
});
|
|
92
|
+
return () => {
|
|
93
|
+
closed = true;
|
|
94
|
+
stream.close();
|
|
95
|
+
};
|
|
96
|
+
}, [adapter, projectId]);
|
|
97
|
+
return rows;
|
|
98
|
+
}
|
|
35
99
|
var NAMED_KEYS = /* @__PURE__ */ new Set([
|
|
36
100
|
"Enter",
|
|
37
101
|
"Tab",
|
|
@@ -240,7 +304,7 @@ function BrowserShell({
|
|
|
240
304
|
children: /* @__PURE__ */ jsx(Reload, {})
|
|
241
305
|
}
|
|
242
306
|
),
|
|
243
|
-
/* @__PURE__ */ jsx(
|
|
307
|
+
(onToggleControl || hasControl) && /* @__PURE__ */ jsx(
|
|
244
308
|
"button",
|
|
245
309
|
{
|
|
246
310
|
type: "button",
|
|
@@ -758,11 +822,26 @@ function ConfirmDialog({
|
|
|
758
822
|
}
|
|
759
823
|
);
|
|
760
824
|
}
|
|
825
|
+
function ComputerBrowserPane({
|
|
826
|
+
available,
|
|
827
|
+
readOnly,
|
|
828
|
+
draw
|
|
829
|
+
}) {
|
|
830
|
+
return /* @__PURE__ */ jsx(
|
|
831
|
+
"div",
|
|
832
|
+
{
|
|
833
|
+
"data-testid": "browser-pane",
|
|
834
|
+
className: "flex h-full min-h-0 flex-col items-center justify-center gap-3 bg-background p-6 text-center text-sm text-muted-foreground",
|
|
835
|
+
children: draw ? draw({ available, readOnly }) : available ? "The browser is open on the chat's computer." : "The chat's computer has no supported browser."
|
|
836
|
+
}
|
|
837
|
+
);
|
|
838
|
+
}
|
|
761
839
|
function BrowserPane({
|
|
762
840
|
sessionId,
|
|
763
841
|
state,
|
|
764
842
|
adapter,
|
|
765
|
-
onClose
|
|
843
|
+
onClose,
|
|
844
|
+
readOnly = false
|
|
766
845
|
}) {
|
|
767
846
|
const [fullscreenOpen, setFullscreenOpen] = useState(false);
|
|
768
847
|
const [openFullscreenOnControl, setOpenFullscreenOnControl] = useState(false);
|
|
@@ -819,8 +898,8 @@ function BrowserPane({
|
|
|
819
898
|
src: shellUrl,
|
|
820
899
|
testId,
|
|
821
900
|
hasControl: localControlActive,
|
|
822
|
-
onToggleControl: hasControlAdapter ? () => void control.toggleControl() : void 0,
|
|
823
|
-
onClose: onClose ? () => control.setConfirmOpen(true) : void 0,
|
|
901
|
+
onToggleControl: hasControlAdapter && !readOnly ? () => void control.toggleControl() : void 0,
|
|
902
|
+
onClose: onClose && !readOnly ? () => control.setConfirmOpen(true) : void 0,
|
|
824
903
|
onMaximize: fullscreenOpen ? void 0 : () => setFullscreenOpen(true),
|
|
825
904
|
onDisconnect: () => setLocalControlActive(false)
|
|
826
905
|
}
|
|
@@ -3931,13 +4010,13 @@ function Textarea({ className, ...props }) {
|
|
|
3931
4010
|
var MAX_REASON_LENGTH = 500;
|
|
3932
4011
|
function ExpertToolBlock({ tc }) {
|
|
3933
4012
|
const [expanded, setExpanded] = useState(false);
|
|
3934
|
-
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
4013
|
+
const { adapter, sessionId, readOnly } = useAgentChatAdapterContext();
|
|
3935
4014
|
const [pending, setPending] = useState(null);
|
|
3936
4015
|
const [error, setError] = useState(null);
|
|
3937
4016
|
const [reasonDraft, setReasonDraft] = useState(null);
|
|
3938
4017
|
const rating = tc.expertFeedback?.rating ?? pending;
|
|
3939
4018
|
const alreadyRated = tc.expertFeedback !== void 0;
|
|
3940
|
-
const canRate = tc.expertResultEventId !== void 0 && sessionId !== null && adapter.submitExpertFeedback !== void 0 && tc.status !== "running";
|
|
4019
|
+
const canRate = !readOnly && tc.expertResultEventId !== void 0 && sessionId !== null && adapter.submitExpertFeedback !== void 0 && tc.status !== "running";
|
|
3941
4020
|
const submit = async (next, reason) => {
|
|
3942
4021
|
if (sessionId === null || tc.expertResultEventId === void 0 || adapter.submitExpertFeedback === void 0) return;
|
|
3943
4022
|
setPending(next);
|
|
@@ -4293,11 +4372,12 @@ function ConversationalAsk({
|
|
|
4293
4372
|
question,
|
|
4294
4373
|
assistantContent
|
|
4295
4374
|
}) {
|
|
4296
|
-
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
4375
|
+
const { adapter, sessionId, readOnly } = useAgentChatAdapterContext();
|
|
4297
4376
|
const [submitting, setSubmitting] = useState(false);
|
|
4298
4377
|
const [error, setError] = useState(null);
|
|
4299
4378
|
const answered = tc.askUserQuestionAnswers !== void 0;
|
|
4300
|
-
const
|
|
4379
|
+
const open = !answered && tc.status === "running";
|
|
4380
|
+
const pending = open && !readOnly;
|
|
4301
4381
|
const choices = question.choices ?? [];
|
|
4302
4382
|
const showPrompt = useMemo(
|
|
4303
4383
|
() => !promptEchoedInContent(assistantContent, question.prompt),
|
|
@@ -4359,7 +4439,7 @@ function ConversationalAsk({
|
|
|
4359
4439
|
}
|
|
4360
4440
|
),
|
|
4361
4441
|
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error }),
|
|
4362
|
-
!answered && !
|
|
4442
|
+
!answered && !open && /* @__PURE__ */ jsx("p", { className: "text-xs italic text-muted-foreground/70", children: "No answer recorded." })
|
|
4363
4443
|
] });
|
|
4364
4444
|
}
|
|
4365
4445
|
function QuickReply({
|
|
@@ -4393,14 +4473,14 @@ function BatchAsk({
|
|
|
4393
4473
|
questions,
|
|
4394
4474
|
viewMode
|
|
4395
4475
|
}) {
|
|
4396
|
-
const { adapter, sessionId } = useAgentChatAdapterContext();
|
|
4476
|
+
const { adapter, sessionId, readOnly } = useAgentChatAdapterContext();
|
|
4397
4477
|
const [active, setActive] = useState(0);
|
|
4398
4478
|
const [selections, setSelections] = useState(
|
|
4399
4479
|
() => questions.map(emptySelection)
|
|
4400
4480
|
);
|
|
4401
4481
|
const [submitting, setSubmitting] = useState(false);
|
|
4402
4482
|
const [error, setError] = useState(null);
|
|
4403
|
-
const locked = tc.askUserQuestionAnswers !== void 0 || tc.status !== "running";
|
|
4483
|
+
const locked = readOnly || tc.askUserQuestionAnswers !== void 0 || tc.status !== "running";
|
|
4404
4484
|
useEffect(() => {
|
|
4405
4485
|
if (active >= questions.length && questions.length > 0) setActive(0);
|
|
4406
4486
|
}, [active, questions.length]);
|
|
@@ -4700,7 +4780,7 @@ function BatchAskLocked({
|
|
|
4700
4780
|
);
|
|
4701
4781
|
const cancelled = !answers && tc.status !== "running";
|
|
4702
4782
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-3 py-2 text-sm max-w-2xl", children: [
|
|
4703
|
-
/* @__PURE__ */ jsx("div", { className: "mb-1 text-xs text-muted-foreground", children: cancelled ? "Clarification cancelled" : "Clarification answered" }),
|
|
4783
|
+
/* @__PURE__ */ jsx("div", { className: "mb-1 text-xs text-muted-foreground", children: cancelled ? "Clarification cancelled" : answers ? "Clarification answered" : "Waiting for an answer" }),
|
|
4704
4784
|
/* @__PURE__ */ jsx("ul", { className: "space-y-1.5", children: questions.map((q, i) => {
|
|
4705
4785
|
const a = byPrompt.get(q.prompt);
|
|
4706
4786
|
return /* @__PURE__ */ jsxs("li", { className: "text-sm", children: [
|
|
@@ -5939,6 +6019,59 @@ function CommandItem({
|
|
|
5939
6019
|
}
|
|
5940
6020
|
);
|
|
5941
6021
|
}
|
|
6022
|
+
function DropdownMenu({
|
|
6023
|
+
...props
|
|
6024
|
+
}) {
|
|
6025
|
+
return /* @__PURE__ */ jsx(DropdownMenu$1.Root, { "data-slot": "dropdown-menu", ...props });
|
|
6026
|
+
}
|
|
6027
|
+
function DropdownMenuTrigger({
|
|
6028
|
+
...props
|
|
6029
|
+
}) {
|
|
6030
|
+
return /* @__PURE__ */ jsx(
|
|
6031
|
+
DropdownMenu$1.Trigger,
|
|
6032
|
+
{
|
|
6033
|
+
"data-slot": "dropdown-menu-trigger",
|
|
6034
|
+
...props
|
|
6035
|
+
}
|
|
6036
|
+
);
|
|
6037
|
+
}
|
|
6038
|
+
function DropdownMenuContent({
|
|
6039
|
+
className,
|
|
6040
|
+
align = "start",
|
|
6041
|
+
sideOffset = 4,
|
|
6042
|
+
...props
|
|
6043
|
+
}) {
|
|
6044
|
+
return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { children: /* @__PURE__ */ jsx(
|
|
6045
|
+
DropdownMenu$1.Content,
|
|
6046
|
+
{
|
|
6047
|
+
"data-slot": "dropdown-menu-content",
|
|
6048
|
+
sideOffset,
|
|
6049
|
+
align,
|
|
6050
|
+
className: cn("z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) min-w-48 origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-none bg-popover p-1.5 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:overflow-hidden data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
|
|
6051
|
+
...props
|
|
6052
|
+
}
|
|
6053
|
+
) });
|
|
6054
|
+
}
|
|
6055
|
+
function DropdownMenuItem({
|
|
6056
|
+
className,
|
|
6057
|
+
inset,
|
|
6058
|
+
variant = "default",
|
|
6059
|
+
...props
|
|
6060
|
+
}) {
|
|
6061
|
+
return /* @__PURE__ */ jsx(
|
|
6062
|
+
DropdownMenu$1.Item,
|
|
6063
|
+
{
|
|
6064
|
+
"data-slot": "dropdown-menu-item",
|
|
6065
|
+
"data-inset": inset,
|
|
6066
|
+
"data-variant": variant,
|
|
6067
|
+
className: cn(
|
|
6068
|
+
"group/dropdown-menu-item relative flex cursor-default items-center gap-2.5 rounded-none px-3 py-2 text-xs font-medium tracking-wider uppercase outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-9.5 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5 data-[variant=destructive]:*:[svg]:text-destructive",
|
|
6069
|
+
className
|
|
6070
|
+
),
|
|
6071
|
+
...props
|
|
6072
|
+
}
|
|
6073
|
+
);
|
|
6074
|
+
}
|
|
5942
6075
|
function Spinner({ className, ...props }) {
|
|
5943
6076
|
return /* @__PURE__ */ jsx(Loader2Icon, { role: "status", "aria-label": "Loading", className: cn("size-4 animate-spin", className), ...props });
|
|
5944
6077
|
}
|
|
@@ -8215,12 +8348,12 @@ function BrandBeam({
|
|
|
8215
8348
|
borderRadius,
|
|
8216
8349
|
className
|
|
8217
8350
|
}) {
|
|
8218
|
-
const
|
|
8351
|
+
const reducedMotion2 = useSyncExternalStore(
|
|
8219
8352
|
subscribeReducedMotion,
|
|
8220
8353
|
readReducedMotion,
|
|
8221
8354
|
readReducedMotionServer
|
|
8222
8355
|
);
|
|
8223
|
-
const effectiveActive = active && !(
|
|
8356
|
+
const effectiveActive = active && !(reducedMotion2 && ROTATE_SIZES.has(size2));
|
|
8224
8357
|
return /* @__PURE__ */ jsx(
|
|
8225
8358
|
BorderBeam,
|
|
8226
8359
|
{
|
|
@@ -10617,7 +10750,9 @@ var MAX_CPS = 240;
|
|
|
10617
10750
|
var DRAIN_SECONDS = 0.25;
|
|
10618
10751
|
var SNAP_LAG = 800;
|
|
10619
10752
|
var MAX_FRAME_DT = 0.1;
|
|
10753
|
+
var reducedMotion = () => typeof document !== "undefined" && document.documentElement.dataset.motion === "reduced";
|
|
10620
10754
|
function useSmoothStream(target, isStreaming) {
|
|
10755
|
+
const instant = reducedMotion();
|
|
10621
10756
|
const [displayedLen, setDisplayedLen] = useState(
|
|
10622
10757
|
() => isStreaming ? 0 : target.length
|
|
10623
10758
|
);
|
|
@@ -10626,7 +10761,7 @@ function useSmoothStream(target, isStreaming) {
|
|
|
10626
10761
|
useEffect(() => {
|
|
10627
10762
|
setDisplayedLen((cur) => cur > target.length ? target.length : cur);
|
|
10628
10763
|
}, [target]);
|
|
10629
|
-
const isActive = isStreaming || displayedLen < target.length;
|
|
10764
|
+
const isActive = !instant && (isStreaming || displayedLen < target.length);
|
|
10630
10765
|
useEffect(() => {
|
|
10631
10766
|
if (!isActive) return;
|
|
10632
10767
|
let raf = 0;
|
|
@@ -10658,7 +10793,7 @@ function useSmoothStream(target, isStreaming) {
|
|
|
10658
10793
|
raf = requestAnimationFrame(tick);
|
|
10659
10794
|
return () => cancelAnimationFrame(raf);
|
|
10660
10795
|
}, [isActive]);
|
|
10661
|
-
return displayedLen >= target.length ? target : target.slice(0, displayedLen);
|
|
10796
|
+
return instant || displayedLen >= target.length ? target : target.slice(0, displayedLen);
|
|
10662
10797
|
}
|
|
10663
10798
|
|
|
10664
10799
|
// src/runtime/reasoning-tokens.ts
|
|
@@ -11729,6 +11864,304 @@ function ArtifactRow({
|
|
|
11729
11864
|
}
|
|
11730
11865
|
return /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: artifact.label });
|
|
11731
11866
|
}
|
|
11867
|
+
var GROUP_LABEL = {
|
|
11868
|
+
waiting: "Waiting on you",
|
|
11869
|
+
working: "Working",
|
|
11870
|
+
idle: "Idle",
|
|
11871
|
+
resolved: "Resolved"
|
|
11872
|
+
};
|
|
11873
|
+
var STATE_LABEL = {
|
|
11874
|
+
working: "Working",
|
|
11875
|
+
reported: "Reported",
|
|
11876
|
+
failed: "Failed"
|
|
11877
|
+
};
|
|
11878
|
+
var FILES_SHOWN = 3;
|
|
11879
|
+
var MARKS = {
|
|
11880
|
+
landed: null,
|
|
11881
|
+
redoing: "being redone",
|
|
11882
|
+
not_merged: "not merged",
|
|
11883
|
+
undone: "undone"
|
|
11884
|
+
};
|
|
11885
|
+
var changedBy = (by) => by.kind === "you" ? "you" : by.kind === "thread" ? `the thread ${by.title}` : `the routine ${by.name}`;
|
|
11886
|
+
function named(paths) {
|
|
11887
|
+
const names = paths.slice(0, FILES_SHOWN);
|
|
11888
|
+
if (paths.length > FILES_SHOWN) names.push(`${paths.length - FILES_SHOWN} more files`);
|
|
11889
|
+
return names.length === 1 ? names[0] : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
|
|
11890
|
+
}
|
|
11891
|
+
function undoLines(result) {
|
|
11892
|
+
const lines = result.applied.length > 0 ? [`Put back ${named(result.applied)}.`] : [];
|
|
11893
|
+
const picked = result.pickedUp ?? [];
|
|
11894
|
+
if (picked.length > 0) lines.push(`Your changes to ${named(picked)} were recorded first: each is a version in its History.`);
|
|
11895
|
+
for (const { path, by, pruned } of result.skipped.slice(0, FILES_SHOWN)) {
|
|
11896
|
+
lines.push(pruned ? `${path} could not be put back: its version from before is no longer kept.` : by === null ? `${path} was left as it is.` : `${path} was changed after this, by ${changedBy(by)}. It was left as it is. Restore an earlier version from its History.`);
|
|
11897
|
+
}
|
|
11898
|
+
const more = result.skipped.length - FILES_SHOWN;
|
|
11899
|
+
if (more === 1) lines.push("1 more file was left as it is: its History says who changed it.");
|
|
11900
|
+
if (more > 1) lines.push(`${more} more files were left as they are: each one's History says who changed it.`);
|
|
11901
|
+
return lines.length > 0 ? lines : ["Nothing to put back: the files are as they were."];
|
|
11902
|
+
}
|
|
11903
|
+
var ASIDE_WHAT = {
|
|
11904
|
+
copy: "its copy",
|
|
11905
|
+
repository: "its repository",
|
|
11906
|
+
place: "the earlier history at its folder's path, with its threads' copies"
|
|
11907
|
+
};
|
|
11908
|
+
function setAsideWhen(at) {
|
|
11909
|
+
const parts = new Intl.DateTimeFormat("en-GB", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit", hourCycle: "h23" }).formatToParts(new Date(at));
|
|
11910
|
+
const part = (type) => parts.find((found) => found.type === type)?.value ?? "";
|
|
11911
|
+
return `${part("day")} ${part("month")}, ${part("hour")}:${part("minute")}`;
|
|
11912
|
+
}
|
|
11913
|
+
function setAsideLines(aside) {
|
|
11914
|
+
const each = (entries) => (Array.isArray(entries) ? entries : []).flatMap((entry) => {
|
|
11915
|
+
const { kind, at } = typeof entry === "object" && entry !== null ? entry : {};
|
|
11916
|
+
const moment = typeof at === "string" ? Date.parse(at) : NaN;
|
|
11917
|
+
const what = typeof kind === "string" && Object.hasOwn(ASIDE_WHAT, kind) ? ASIDE_WHAT[kind] : void 0;
|
|
11918
|
+
return what !== void 0 && !Number.isNaN(moment) ? [`${what} from ${setAsideWhen(moment)}`] : [];
|
|
11919
|
+
});
|
|
11920
|
+
if (!aside) return [];
|
|
11921
|
+
const count = Number.isSafeInteger(aside.snapshots) && aside.snapshots > 0 ? aside.snapshots : 0;
|
|
11922
|
+
const kept = [...each(aside.kept), ...count > 0 ? [`${count} snapshot${count > 1 ? "s" : ""}`] : []];
|
|
11923
|
+
const gone = each(aside.gone);
|
|
11924
|
+
return [
|
|
11925
|
+
...kept.length > 0 ? [`Kept on its computer: ${kept.join(" \xB7 ")}`] : [],
|
|
11926
|
+
...gone.length > 0 ? [`No longer kept: ${gone.join(" \xB7 ")}`] : []
|
|
11927
|
+
];
|
|
11928
|
+
}
|
|
11929
|
+
function firstLine3(text) {
|
|
11930
|
+
return text?.split("\n").find((line) => line.trim())?.trim() ?? null;
|
|
11931
|
+
}
|
|
11932
|
+
function statusLineOf(report) {
|
|
11933
|
+
for (const line of report?.split("\n") ?? []) {
|
|
11934
|
+
if (/^\s*#{1,6}(\s|$)/.test(line)) continue;
|
|
11935
|
+
const plain = line.replace(/\*\*|__|`/g, "").trim();
|
|
11936
|
+
if (plain) return plain;
|
|
11937
|
+
}
|
|
11938
|
+
return null;
|
|
11939
|
+
}
|
|
11940
|
+
var cardStarts = /* @__PURE__ */ new WeakMap();
|
|
11941
|
+
var startListeners = /* @__PURE__ */ new Set();
|
|
11942
|
+
var startsChanged = 0;
|
|
11943
|
+
var drawnCards = /* @__PURE__ */ new Map();
|
|
11944
|
+
function setCardStart(adapter, card, start) {
|
|
11945
|
+
const starts = cardStarts.get(adapter) ?? /* @__PURE__ */ new Map();
|
|
11946
|
+
cardStarts.set(adapter, starts.set(card, start));
|
|
11947
|
+
startsChanged++;
|
|
11948
|
+
for (const listener of startListeners) listener();
|
|
11949
|
+
}
|
|
11950
|
+
function useCardStarts(adapter) {
|
|
11951
|
+
useSyncExternalStore(
|
|
11952
|
+
(listener) => {
|
|
11953
|
+
startListeners.add(listener);
|
|
11954
|
+
return () => {
|
|
11955
|
+
startListeners.delete(listener);
|
|
11956
|
+
};
|
|
11957
|
+
},
|
|
11958
|
+
() => startsChanged
|
|
11959
|
+
);
|
|
11960
|
+
return cardStarts.get(adapter) ?? /* @__PURE__ */ new Map();
|
|
11961
|
+
}
|
|
11962
|
+
function ThreadCards({ message }) {
|
|
11963
|
+
if (message.worker) return /* @__PURE__ */ jsx(WorkerCard, { worker: message.worker });
|
|
11964
|
+
if (message.proposal) return /* @__PURE__ */ jsx(ProposalCard, { proposal: message.proposal });
|
|
11965
|
+
return null;
|
|
11966
|
+
}
|
|
11967
|
+
function WorkerCard({ worker }) {
|
|
11968
|
+
const { adapter, projectId, onFileSelect, onOpenSession, threadRows } = useAgentChatAdapterContext();
|
|
11969
|
+
const undoKey = `undo:${worker.id}`;
|
|
11970
|
+
const undone = useCardStarts(adapter).get(undoKey);
|
|
11971
|
+
const live = threadRows?.[worker.id];
|
|
11972
|
+
const group = live?.group && Object.hasOwn(GROUP_LABEL, live.group) ? live.group : void 0;
|
|
11973
|
+
const status = live ? [group && GROUP_LABEL[group], live.progress && `${live.progress.done}/${live.progress.total}`].filter(Boolean).join(" \xB7 ") : STATE_LABEL[worker.state];
|
|
11974
|
+
const statusLine = live ? live.statusLine : statusLineOf(worker.report);
|
|
11975
|
+
const files = live ? Array.isArray(live.files) ? live.files : [] : worker.files;
|
|
11976
|
+
const unlisted = live && Number.isSafeInteger(live.moreFiles) && live.moreFiles > 0 ? live.moreFiles : 0;
|
|
11977
|
+
const more = Math.max(files.length - FILES_SHOWN, 0) + unlisted;
|
|
11978
|
+
const setAside = setAsideLines(live?.setAside);
|
|
11979
|
+
const name = worker.title ?? firstLine3(worker.goal);
|
|
11980
|
+
const view = worker.title !== null ? "View thread" : "View worker";
|
|
11981
|
+
const canUndo = !!live && !!projectId && !!adapter.undoProjectChanges;
|
|
11982
|
+
const undoingNow = undone?.state === "undoing";
|
|
11983
|
+
const undo = async (target) => {
|
|
11984
|
+
if (undoingNow) return;
|
|
11985
|
+
setCardStart(adapter, undoKey, { state: "undoing" });
|
|
11986
|
+
try {
|
|
11987
|
+
setCardStart(adapter, undoKey, { state: "undone", result: await adapter.undoProjectChanges({ projectId, target }) });
|
|
11988
|
+
} catch (error) {
|
|
11989
|
+
setCardStart(adapter, undoKey, { state: "not_undone", error: error instanceof Error ? error.message : "The change could not be undone." });
|
|
11990
|
+
}
|
|
11991
|
+
};
|
|
11992
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": "worker-card", "data-group": group, className: "my-2 rounded-lg border border-border px-3 py-2 text-sm", children: [
|
|
11993
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
11994
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-medium text-foreground", title: name ?? void 0, children: /* @__PURE__ */ jsx("bdi", { children: name }) }),
|
|
11995
|
+
/* @__PURE__ */ jsx("span", { "data-testid": "worker-card-status", className: "shrink-0 text-xs text-muted-foreground", children: status })
|
|
11996
|
+
] }),
|
|
11997
|
+
statusLine && /* @__PURE__ */ jsx("p", { className: "truncate text-foreground/70", title: statusLine, children: /* @__PURE__ */ jsx("bdi", { children: statusLine }) }),
|
|
11998
|
+
files.length + unlisted > 0 && /* @__PURE__ */ jsxs("ul", { className: "mt-1 flex flex-wrap gap-x-3 text-xs", children: [
|
|
11999
|
+
files.slice(0, FILES_SHOWN).map((file) => {
|
|
12000
|
+
const landing = "landing" in file && file.landing && Object.hasOwn(MARKS, file.landing) ? file.landing : null;
|
|
12001
|
+
const mark = landing ? MARKS[landing] : null;
|
|
12002
|
+
return (
|
|
12003
|
+
// A long name is cut, its mark never.
|
|
12004
|
+
/* @__PURE__ */ jsxs("li", { className: "flex min-w-0 max-w-full", title: file.label, children: [
|
|
12005
|
+
file.kind === "file" && onFileSelect ? /* @__PURE__ */ jsx(
|
|
12006
|
+
"button",
|
|
12007
|
+
{
|
|
12008
|
+
type: "button",
|
|
12009
|
+
className: "min-w-0 truncate underline",
|
|
12010
|
+
onClick: () => onFileSelect(file.ref),
|
|
12011
|
+
children: /* @__PURE__ */ jsx("bdi", { children: file.label })
|
|
12012
|
+
}
|
|
12013
|
+
) : /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: /* @__PURE__ */ jsx("bdi", { children: file.label }) }),
|
|
12014
|
+
mark && /* @__PURE__ */ jsx("span", { "data-mark": landing, className: "shrink-0 whitespace-pre text-muted-foreground", children: ` \xB7 ${mark}` })
|
|
12015
|
+
] }, `${file.kind}:${file.ref}`)
|
|
12016
|
+
);
|
|
12017
|
+
}),
|
|
12018
|
+
more > 0 && /* @__PURE__ */ jsxs("li", { children: [
|
|
12019
|
+
"+",
|
|
12020
|
+
more,
|
|
12021
|
+
" more"
|
|
12022
|
+
] })
|
|
12023
|
+
] }),
|
|
12024
|
+
setAside.length > 0 && /* @__PURE__ */ jsx("div", { "data-testid": "worker-card-set-aside", className: "mt-1 text-xs text-muted-foreground", children: setAside.map((line, at) => /* @__PURE__ */ jsx("p", { children: line }, at)) }),
|
|
12025
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1", children: [
|
|
12026
|
+
onOpenSession && /* @__PURE__ */ jsx(Button, { size: "xs", variant: "ghost", "aria-label": name ? `${view} ${name}` : void 0, onClick: () => onOpenSession(worker.id), children: view }),
|
|
12027
|
+
canUndo && live.landingId && /* @__PURE__ */ jsx(
|
|
12028
|
+
Button,
|
|
12029
|
+
{
|
|
12030
|
+
size: "xs",
|
|
12031
|
+
variant: "ghost",
|
|
12032
|
+
disabled: undoingNow,
|
|
12033
|
+
"aria-label": name ? `Undo ${name}'s latest changes` : void 0,
|
|
12034
|
+
onClick: () => void undo({ landingId: live.landingId }),
|
|
12035
|
+
children: "Undo"
|
|
12036
|
+
}
|
|
12037
|
+
),
|
|
12038
|
+
canUndo && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
12039
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "xs", variant: "ghost", "aria-label": name ? `More for ${name}` : "More", children: "\u2026" }) }),
|
|
12040
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { children: /* @__PURE__ */ jsx(DropdownMenuItem, { disabled: undoingNow, onSelect: () => void undo({ threadId: worker.id }), children: "Undo this thread's changes" }) })
|
|
12041
|
+
] })
|
|
12042
|
+
] }),
|
|
12043
|
+
canUndo && /* @__PURE__ */ jsx("div", { role: "status", className: "text-xs text-foreground/70", children: undone?.state === "undone" && undoLines(undone.result).map((line, at) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("bdi", { children: line }) }, at)) }),
|
|
12044
|
+
canUndo && undone?.state === "not_undone" && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-xs text-destructive", children: /* @__PURE__ */ jsx("bdi", { children: undone.error }) })
|
|
12045
|
+
] });
|
|
12046
|
+
}
|
|
12047
|
+
function ProposalCard({ proposal }) {
|
|
12048
|
+
const { adapter, projectId, onOpenSession } = useAgentChatAdapterContext();
|
|
12049
|
+
const starts = useCardStarts(adapter);
|
|
12050
|
+
const startOf = (key) => starts.get(`${proposal.proposalId}:${key}`);
|
|
12051
|
+
const told = (key, start2) => setCardStart(adapter, `${proposal.proposalId}:${key}`, start2);
|
|
12052
|
+
const started = {};
|
|
12053
|
+
for (const { key } of proposal.threads) {
|
|
12054
|
+
const start2 = startOf(key);
|
|
12055
|
+
if (start2?.state === "started") started[key] = start2.threadId;
|
|
12056
|
+
}
|
|
12057
|
+
Object.assign(started, proposal.started);
|
|
12058
|
+
const startingAt = (key) => {
|
|
12059
|
+
const start2 = startOf(key);
|
|
12060
|
+
return start2?.state === "starting" ? start2.where : void 0;
|
|
12061
|
+
};
|
|
12062
|
+
const starting = (key) => startingAt(key) !== void 0;
|
|
12063
|
+
const canStart = !!projectId && !!adapter.startProposedThread;
|
|
12064
|
+
const canStartHere = !!projectId && !!adapter.startLocalThread;
|
|
12065
|
+
const viewButtons = useRef({});
|
|
12066
|
+
useEffect(() => {
|
|
12067
|
+
drawnCards.set(proposal.proposalId, (drawnCards.get(proposal.proposalId) ?? 0) + 1);
|
|
12068
|
+
return () => {
|
|
12069
|
+
const left = (drawnCards.get(proposal.proposalId) ?? 1) - 1;
|
|
12070
|
+
if (left > 0) drawnCards.set(proposal.proposalId, left);
|
|
12071
|
+
else drawnCards.delete(proposal.proposalId);
|
|
12072
|
+
};
|
|
12073
|
+
}, [proposal.proposalId]);
|
|
12074
|
+
useEffect(() => {
|
|
12075
|
+
for (const { key } of proposal.threads) {
|
|
12076
|
+
const start2 = startOf(key);
|
|
12077
|
+
if (start2?.state !== "started" || !start2.focus) continue;
|
|
12078
|
+
if (!document.activeElement || document.activeElement === document.body) viewButtons.current[key]?.focus();
|
|
12079
|
+
told(key, { ...start2, focus: false });
|
|
12080
|
+
}
|
|
12081
|
+
});
|
|
12082
|
+
const start = async (key, title) => {
|
|
12083
|
+
told(key, { state: "starting", where: title === void 0 ? "cloud" : "device" });
|
|
12084
|
+
try {
|
|
12085
|
+
const card = { projectId, proposalId: proposal.proposalId, key };
|
|
12086
|
+
const row = title === void 0 ? await adapter.startProposedThread(card) : await adapter.startLocalThread({ ...card, title });
|
|
12087
|
+
told(key, { state: "started", threadId: row.id, focus: drawnCards.has(proposal.proposalId) });
|
|
12088
|
+
} catch (error) {
|
|
12089
|
+
told(key, { state: "failed", error: error instanceof Error ? error.message : "The thread could not be started." });
|
|
12090
|
+
}
|
|
12091
|
+
};
|
|
12092
|
+
const startable = proposal.threads.filter(
|
|
12093
|
+
(thread) => thread.where === "cloud" && !started[thread.key] && !starting(thread.key)
|
|
12094
|
+
);
|
|
12095
|
+
const startAll = async (keys) => {
|
|
12096
|
+
for (const key of keys) told(key, { state: "starting", where: "cloud" });
|
|
12097
|
+
for (const key of keys) await start(key);
|
|
12098
|
+
};
|
|
12099
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": "thread-proposal-card", className: "my-2 rounded-lg border border-border px-3 py-2 text-sm", children: [
|
|
12100
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
12101
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 font-medium text-foreground", children: "Proposed threads" }),
|
|
12102
|
+
canStart && startable.length > 1 && /* @__PURE__ */ jsx(Button, { size: "xs", onClick: () => void startAll(startable.map((thread) => thread.key)), children: "Start all" })
|
|
12103
|
+
] }),
|
|
12104
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-1 space-y-2", children: proposal.threads.map((thread) => {
|
|
12105
|
+
const threadId = started[thread.key];
|
|
12106
|
+
const tried = startOf(thread.key);
|
|
12107
|
+
return /* @__PURE__ */ jsxs("li", { "data-testid": "proposed-thread", children: [
|
|
12108
|
+
/* @__PURE__ */ jsx("div", { className: "break-words font-medium text-foreground", children: /* @__PURE__ */ jsx("bdi", { children: thread.title }) }),
|
|
12109
|
+
/* @__PURE__ */ jsx("p", { className: "line-clamp-2 break-words text-foreground/70", children: /* @__PURE__ */ jsx("bdi", { children: thread.goal }) }),
|
|
12110
|
+
/* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
12111
|
+
/* @__PURE__ */ jsx("span", { role: "status", children: threadId ? "Started" : "" }),
|
|
12112
|
+
threadId ? onOpenSession && /* @__PURE__ */ jsx(
|
|
12113
|
+
Button,
|
|
12114
|
+
{
|
|
12115
|
+
ref: (node) => {
|
|
12116
|
+
viewButtons.current[thread.key] = node;
|
|
12117
|
+
},
|
|
12118
|
+
size: "xs",
|
|
12119
|
+
variant: "ghost",
|
|
12120
|
+
"aria-label": `View thread ${thread.title}`,
|
|
12121
|
+
onClick: () => onOpenSession(threadId),
|
|
12122
|
+
children: "View thread"
|
|
12123
|
+
}
|
|
12124
|
+
) : thread.where === "device" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12125
|
+
/* @__PURE__ */ jsx("span", { children: canStartHere ? "Allow Surogate to work in a folder on your device" : "This works in a folder on your device, which needs Surogate Desktop" }),
|
|
12126
|
+
canStartHere && /* @__PURE__ */ jsx(
|
|
12127
|
+
Button,
|
|
12128
|
+
{
|
|
12129
|
+
size: "xs",
|
|
12130
|
+
variant: "outline",
|
|
12131
|
+
disabled: starting(thread.key),
|
|
12132
|
+
"aria-label": `${startingAt(thread.key) === "device" ? "Starting" : "Allow"} ${thread.title}`,
|
|
12133
|
+
onClick: () => void start(thread.key, thread.title),
|
|
12134
|
+
children: startingAt(thread.key) === "device" ? "Starting\u2026" : "Allow"
|
|
12135
|
+
}
|
|
12136
|
+
),
|
|
12137
|
+
canStart && /* @__PURE__ */ jsx(
|
|
12138
|
+
Button,
|
|
12139
|
+
{
|
|
12140
|
+
size: "xs",
|
|
12141
|
+
variant: "ghost",
|
|
12142
|
+
disabled: starting(thread.key),
|
|
12143
|
+
"aria-label": startingAt(thread.key) === "cloud" ? `Starting ${thread.title}` : `Run ${thread.title} in the cloud instead`,
|
|
12144
|
+
onClick: () => void start(thread.key),
|
|
12145
|
+
children: startingAt(thread.key) === "cloud" ? "Starting\u2026" : "Run in the cloud instead"
|
|
12146
|
+
}
|
|
12147
|
+
)
|
|
12148
|
+
] }) : canStart ? /* @__PURE__ */ jsx(
|
|
12149
|
+
Button,
|
|
12150
|
+
{
|
|
12151
|
+
size: "xs",
|
|
12152
|
+
variant: "outline",
|
|
12153
|
+
disabled: starting(thread.key),
|
|
12154
|
+
"aria-label": `${starting(thread.key) ? "Starting" : "Start"} ${thread.title}`,
|
|
12155
|
+
onClick: () => void start(thread.key),
|
|
12156
|
+
children: starting(thread.key) ? "Starting\u2026" : "Start"
|
|
12157
|
+
}
|
|
12158
|
+
) : null
|
|
12159
|
+
] }),
|
|
12160
|
+
!threadId && tried?.state === "failed" && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-xs text-destructive", children: tried.error })
|
|
12161
|
+
] }, thread.key);
|
|
12162
|
+
}) })
|
|
12163
|
+
] });
|
|
12164
|
+
}
|
|
11732
12165
|
var WORKING_ON_IT_DELAY_MS = 250;
|
|
11733
12166
|
function hasUserFacingAskContent(msg) {
|
|
11734
12167
|
return !!msg.toolCalls?.some((tc) => tc.toolName === "ask_user_question");
|
|
@@ -11784,6 +12217,9 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
11784
12217
|
originatingSessionId
|
|
11785
12218
|
}];
|
|
11786
12219
|
}
|
|
12220
|
+
if (msg.systemKind === "worker" || msg.systemKind === "thread_proposal") {
|
|
12221
|
+
return [{ kind: "thread_card", key: msg.id, message: msg }];
|
|
12222
|
+
}
|
|
11787
12223
|
if (msg.systemKind === "browser_marker" || msg.systemKind === "browser_marker_warning") {
|
|
11788
12224
|
return [{
|
|
11789
12225
|
kind: "browser_marker",
|
|
@@ -12015,6 +12451,9 @@ function OrphanSystemMarker({
|
|
|
12015
12451
|
if (message.systemKind === "error" && message.errorInfo) {
|
|
12016
12452
|
return /* @__PURE__ */ jsx("div", { className: "mx-auto my-2 w-full max-w-4xl", children: /* @__PURE__ */ jsx(ErrorMessage, { errorInfo: message.errorInfo, onRetry }) });
|
|
12017
12453
|
}
|
|
12454
|
+
if (message.systemKind === "worker" || message.systemKind === "thread_proposal") {
|
|
12455
|
+
return /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-4xl px-4", children: /* @__PURE__ */ jsx(ThreadCards, { message }) });
|
|
12456
|
+
}
|
|
12018
12457
|
return null;
|
|
12019
12458
|
}
|
|
12020
12459
|
function CancelledToolRow({ tc }) {
|
|
@@ -12119,6 +12558,15 @@ function TimelineEntryItem({
|
|
|
12119
12558
|
) })
|
|
12120
12559
|
] });
|
|
12121
12560
|
}
|
|
12561
|
+
if (entry.kind === "thread_card") {
|
|
12562
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
12563
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
12564
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
12565
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-foreground/30" })
|
|
12566
|
+
] }),
|
|
12567
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(ThreadCards, { message: entry.message }) })
|
|
12568
|
+
] });
|
|
12569
|
+
}
|
|
12122
12570
|
if (entry.kind === "skill_invoked") {
|
|
12123
12571
|
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
12124
12572
|
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
@@ -12731,7 +13179,9 @@ function ChatThread({
|
|
|
12731
13179
|
researchSources = [],
|
|
12732
13180
|
hideTurnSummary = false,
|
|
12733
13181
|
agentId,
|
|
12734
|
-
onOpenIntegrations
|
|
13182
|
+
onOpenIntegrations,
|
|
13183
|
+
deviceWait = null,
|
|
13184
|
+
composerFooter
|
|
12735
13185
|
}) {
|
|
12736
13186
|
const groups = useMemo(() => groupMessages(messages), [messages]);
|
|
12737
13187
|
const activeAssistantId = useMemo(() => {
|
|
@@ -12807,6 +13257,18 @@ function ChatThread({
|
|
|
12807
13257
|
return null;
|
|
12808
13258
|
}, [messages]);
|
|
12809
13259
|
const composerArea = /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-4xl px-3 sm:px-6 pb-3 sm:pb-5 pt-3", children: [
|
|
13260
|
+
/* @__PURE__ */ jsx(
|
|
13261
|
+
"div",
|
|
13262
|
+
{
|
|
13263
|
+
role: "status",
|
|
13264
|
+
"data-testid": "device-wait",
|
|
13265
|
+
className: deviceWait ? "mb-2 flex items-center gap-2 rounded-lg border border-line bg-card px-3 py-2 text-sm text-muted-foreground" : void 0,
|
|
13266
|
+
children: deviceWait && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13267
|
+
/* @__PURE__ */ jsx(LaptopIcon, { className: "size-4 shrink-0", "aria-hidden": "true" }),
|
|
13268
|
+
deviceWait.reason === "copying" ? `Making this thread's copy of ${deviceWait.folder || "its folder"}\u2026` : `Waiting for ${deviceWait.deviceName || "your computer"}. The chat goes on once it is back online.`
|
|
13269
|
+
] })
|
|
13270
|
+
}
|
|
13271
|
+
),
|
|
12810
13272
|
retryIndicator && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(RetryBanner, { indicator: retryIndicator }) }),
|
|
12811
13273
|
researchSources.length > 0 && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(ResearchSourcesPanel, { sources: researchSources }) }),
|
|
12812
13274
|
(paneCards?.browser || paneCards?.files) && // Layers sliding out from behind the prompt box: each card is
|
|
@@ -12891,6 +13353,7 @@ function ChatThread({
|
|
|
12891
13353
|
compressEnabled
|
|
12892
13354
|
}
|
|
12893
13355
|
),
|
|
13356
|
+
composerFooter,
|
|
12894
13357
|
onOpenIntegrations && /* @__PURE__ */ jsx(
|
|
12895
13358
|
IntegrationsBandSlot,
|
|
12896
13359
|
{
|
|
@@ -12905,76 +13368,80 @@ function ChatThread({
|
|
|
12905
13368
|
// input floating mid-screen with dead space under it, and the keyboard
|
|
12906
13369
|
// then opens across that gap. There the composer keeps its usual place
|
|
12907
13370
|
// at the bottom edge and the greeting takes the space above it.
|
|
12908
|
-
|
|
13371
|
+
// data-transcript: the host's transcript settings shape this, the composer with it.
|
|
13372
|
+
/* @__PURE__ */ jsxs("div", { "data-transcript": "", className: "flex flex-1 flex-col items-center justify-end overflow-hidden bg-background px-3 text-base md:justify-center", children: [
|
|
12909
13373
|
/* @__PURE__ */ jsx("div", { className: "flex w-full flex-1 flex-col justify-center md:flex-none", children: /* @__PURE__ */ jsx("h2", { className: "mb-6 text-center text-2xl font-bold text-foreground md:mb-8", children: "What should we do ?" }) }),
|
|
12910
13374
|
/* @__PURE__ */ jsx("div", { className: "w-full", children: composerArea })
|
|
12911
13375
|
] })
|
|
12912
13376
|
);
|
|
12913
13377
|
}
|
|
12914
|
-
return
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
{
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
groups.map((group) => {
|
|
12925
|
-
if (group.role === "user") {
|
|
12926
|
-
const msg = group.messages[0];
|
|
12927
|
-
return /* @__PURE__ */ jsx(
|
|
12928
|
-
ChatMessage,
|
|
12929
|
-
{
|
|
12930
|
-
message: msg,
|
|
12931
|
-
onFileSelect
|
|
12932
|
-
},
|
|
12933
|
-
msg.id
|
|
12934
|
-
);
|
|
13378
|
+
return (
|
|
13379
|
+
// data-transcript: the host's transcript settings shape this, the composer with it.
|
|
13380
|
+
/* @__PURE__ */ jsxs("div", { "data-transcript": "", className: "flex flex-1 flex-col overflow-hidden bg-background text-base", children: [
|
|
13381
|
+
/* @__PURE__ */ jsxs(Conversation, { className: "relative flex-1 min-h-0", children: [
|
|
13382
|
+
/* @__PURE__ */ jsx(ConversationContent, { className: "mx-auto w-full max-w-4xl", children: messages.length === 0 && isLoadingHistory ? /* @__PURE__ */ jsx(
|
|
13383
|
+
ConversationEmptyState,
|
|
13384
|
+
{
|
|
13385
|
+
icon: /* @__PURE__ */ jsx(MessageSquareIcon, { className: "size-8 opacity-40" }),
|
|
13386
|
+
title: "Loading conversation",
|
|
13387
|
+
description: "Fetching the session history."
|
|
12935
13388
|
}
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
if (
|
|
12939
|
-
|
|
13389
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
13390
|
+
groups.map((group) => {
|
|
13391
|
+
if (group.role === "user") {
|
|
13392
|
+
const msg = group.messages[0];
|
|
13393
|
+
return /* @__PURE__ */ jsx(
|
|
13394
|
+
ChatMessage,
|
|
13395
|
+
{
|
|
13396
|
+
message: msg,
|
|
13397
|
+
onFileSelect
|
|
13398
|
+
},
|
|
13399
|
+
msg.id
|
|
13400
|
+
);
|
|
13401
|
+
}
|
|
13402
|
+
if (group.role === "system") {
|
|
13403
|
+
const msg = group.messages[0];
|
|
13404
|
+
if (viewMode === "simple" && msg.systemKind === "skill_invoked") {
|
|
13405
|
+
return null;
|
|
13406
|
+
}
|
|
13407
|
+
const groupRetry2 = msg.id === activeFailureId ? onRetry : void 0;
|
|
13408
|
+
return /* @__PURE__ */ jsx(
|
|
13409
|
+
OrphanSystemMarker,
|
|
13410
|
+
{
|
|
13411
|
+
message: msg,
|
|
13412
|
+
sessionId,
|
|
13413
|
+
onRetry: groupRetry2
|
|
13414
|
+
},
|
|
13415
|
+
msg.id
|
|
13416
|
+
);
|
|
12940
13417
|
}
|
|
12941
|
-
const
|
|
13418
|
+
const groupTail = group.messages[group.messages.length - 1];
|
|
13419
|
+
const groupRetry = groupTail.id === activeFailureId ? onRetry : void 0;
|
|
12942
13420
|
return /* @__PURE__ */ jsx(
|
|
12943
|
-
|
|
13421
|
+
AssistantGroup,
|
|
12944
13422
|
{
|
|
12945
|
-
|
|
13423
|
+
messages: group.messages,
|
|
13424
|
+
activeAssistantId,
|
|
13425
|
+
lastGlobalIndex: group.lastGlobalIndex,
|
|
13426
|
+
totalMessages: messages.length,
|
|
13427
|
+
isRunning,
|
|
12946
13428
|
sessionId,
|
|
12947
|
-
|
|
13429
|
+
artifactFallbacks,
|
|
13430
|
+
onFileSelect,
|
|
13431
|
+
onRetry: groupRetry,
|
|
13432
|
+
viewMode,
|
|
13433
|
+
hideTurnSummary
|
|
12948
13434
|
},
|
|
12949
|
-
|
|
13435
|
+
group.messages[0].id
|
|
12950
13436
|
);
|
|
12951
|
-
}
|
|
12952
|
-
|
|
12953
|
-
|
|
12954
|
-
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
|
|
12958
|
-
|
|
12959
|
-
lastGlobalIndex: group.lastGlobalIndex,
|
|
12960
|
-
totalMessages: messages.length,
|
|
12961
|
-
isRunning,
|
|
12962
|
-
sessionId,
|
|
12963
|
-
artifactFallbacks,
|
|
12964
|
-
onFileSelect,
|
|
12965
|
-
onRetry: groupRetry,
|
|
12966
|
-
viewMode,
|
|
12967
|
-
hideTurnSummary
|
|
12968
|
-
},
|
|
12969
|
-
group.messages[0].id
|
|
12970
|
-
);
|
|
12971
|
-
}),
|
|
12972
|
-
showWorkingOnIt && /* @__PURE__ */ jsx(WorkingOnItIndicator, { activity: orbActivity })
|
|
12973
|
-
] }) }),
|
|
12974
|
-
/* @__PURE__ */ jsx(ConversationScrollButton, {})
|
|
12975
|
-
] }),
|
|
12976
|
-
composerArea
|
|
12977
|
-
] });
|
|
13437
|
+
}),
|
|
13438
|
+
showWorkingOnIt && /* @__PURE__ */ jsx(WorkingOnItIndicator, { activity: orbActivity })
|
|
13439
|
+
] }) }),
|
|
13440
|
+
/* @__PURE__ */ jsx(ConversationScrollButton, {})
|
|
13441
|
+
] }),
|
|
13442
|
+
composerArea
|
|
13443
|
+
] })
|
|
13444
|
+
);
|
|
12978
13445
|
}
|
|
12979
13446
|
function IntegrationsBandSlot({
|
|
12980
13447
|
agentId,
|
|
@@ -13001,6 +13468,7 @@ var WORKSPACE_MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
13001
13468
|
]);
|
|
13002
13469
|
var AGENT_CHAT_LISTENED_EVENTS = [
|
|
13003
13470
|
"user.message",
|
|
13471
|
+
"coordinator.message",
|
|
13004
13472
|
"llm.request",
|
|
13005
13473
|
"llm.response",
|
|
13006
13474
|
"llm.thinking",
|
|
@@ -13032,63 +13500,286 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
13032
13500
|
"artifact.updated",
|
|
13033
13501
|
"browser.provisioned",
|
|
13034
13502
|
"browser.destroyed",
|
|
13503
|
+
"browser.unavailable",
|
|
13035
13504
|
"browser.control_granted",
|
|
13036
13505
|
"browser.control_returned",
|
|
13037
13506
|
"ask_user_question.response",
|
|
13038
13507
|
"iteration.summary",
|
|
13039
13508
|
"turn.summary",
|
|
13040
|
-
"loop.result"
|
|
13509
|
+
"loop.result",
|
|
13510
|
+
"device.waiting",
|
|
13511
|
+
"device.resumed",
|
|
13512
|
+
"worker.spawned",
|
|
13513
|
+
"worker.complete",
|
|
13514
|
+
"worker.failed",
|
|
13515
|
+
"thread.proposed"
|
|
13041
13516
|
];
|
|
13042
13517
|
var AGENT_CHAT_LISTENED_EVENT_SET = new Set(
|
|
13043
13518
|
AGENT_CHAT_LISTENED_EVENTS
|
|
13044
13519
|
);
|
|
13045
13520
|
|
|
13046
|
-
// src/
|
|
13047
|
-
var
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
reasoningTokens: 0,
|
|
13051
|
-
cachedInputTokens: 0,
|
|
13052
|
-
totalTokens: 0,
|
|
13053
|
-
contextWindow: 0,
|
|
13054
|
-
model: ""
|
|
13055
|
-
};
|
|
13056
|
-
function createInitialAgentChatState(options = {}) {
|
|
13057
|
-
return {
|
|
13058
|
-
messages: [],
|
|
13059
|
-
isRunning: false,
|
|
13060
|
-
isLoadingHistory: options.isLoadingHistory ?? false,
|
|
13061
|
-
tokenUsage: EMPTY_TOKEN_USAGE,
|
|
13062
|
-
retryIndicator: null,
|
|
13063
|
-
lastEventId: 0,
|
|
13064
|
-
sessionDone: false,
|
|
13065
|
-
hadDeltas: false,
|
|
13066
|
-
terminal: false,
|
|
13067
|
-
stopped: false,
|
|
13068
|
-
workspaceRefreshKey: 0,
|
|
13069
|
-
browser: null,
|
|
13070
|
-
viewMode: options.viewMode ?? "simple",
|
|
13071
|
-
researchSources: []
|
|
13072
|
-
};
|
|
13521
|
+
// src/components/missions/mission-derive.ts
|
|
13522
|
+
var ACTIVE_MISSION_STATUSES = /* @__PURE__ */ new Set(["active", "paused"]);
|
|
13523
|
+
function isTerminalMissionStatus(status) {
|
|
13524
|
+
return !ACTIVE_MISSION_STATUSES.has(status);
|
|
13073
13525
|
}
|
|
13074
|
-
function
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13526
|
+
function missionTaskBucket(status) {
|
|
13527
|
+
if (status === "done") return "done";
|
|
13528
|
+
if (status === "blocked") return "blocked";
|
|
13529
|
+
if (status === "failed" || status === "cancelled") {
|
|
13530
|
+
return "failed_or_cancelled";
|
|
13531
|
+
}
|
|
13532
|
+
return "in_flight";
|
|
13533
|
+
}
|
|
13534
|
+
function groupMissionTasksByBucket(tasks) {
|
|
13535
|
+
const buckets = {
|
|
13536
|
+
in_flight: [],
|
|
13537
|
+
done: [],
|
|
13538
|
+
blocked: [],
|
|
13539
|
+
failed_or_cancelled: []
|
|
13080
13540
|
};
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
return nextState;
|
|
13541
|
+
for (const t of tasks) {
|
|
13542
|
+
buckets[missionTaskBucket(t.status)].push(t);
|
|
13084
13543
|
}
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13544
|
+
return buckets;
|
|
13545
|
+
}
|
|
13546
|
+
function deriveMissionWorkerActivityLabel(worker) {
|
|
13547
|
+
const kind = worker.latestEventKind;
|
|
13548
|
+
if (kind === "tool.call" && worker.latestEventSummary) {
|
|
13549
|
+
return `tool: ${truncate4(worker.latestEventSummary, 80)}`;
|
|
13550
|
+
}
|
|
13551
|
+
if (kind === "llm.response") {
|
|
13552
|
+
return "thinking";
|
|
13553
|
+
}
|
|
13554
|
+
if (kind === "tool.result") {
|
|
13555
|
+
return "received tool result";
|
|
13556
|
+
}
|
|
13557
|
+
if (kind && worker.latestEventSummary) {
|
|
13558
|
+
return `${kind}: ${truncate4(worker.latestEventSummary, 60)}`;
|
|
13559
|
+
}
|
|
13560
|
+
return worker.sessionStatus || "active";
|
|
13561
|
+
}
|
|
13562
|
+
function truncate4(s, max) {
|
|
13563
|
+
if (s.length <= max) return s;
|
|
13564
|
+
return `${s.slice(0, max - 1)}\u2026`;
|
|
13565
|
+
}
|
|
13566
|
+
var MISSION_EVENT_CATEGORIES = [
|
|
13567
|
+
"spawn",
|
|
13568
|
+
"output",
|
|
13569
|
+
"done",
|
|
13570
|
+
"verdict",
|
|
13571
|
+
"system"
|
|
13572
|
+
];
|
|
13573
|
+
function missionEventCategory(type) {
|
|
13574
|
+
switch (type) {
|
|
13575
|
+
case "worker.spawned":
|
|
13576
|
+
return "spawn";
|
|
13577
|
+
case "iteration.summary":
|
|
13578
|
+
return "output";
|
|
13579
|
+
case "worker.complete":
|
|
13580
|
+
return "done";
|
|
13581
|
+
case "mission.evaluation.end":
|
|
13582
|
+
return "verdict";
|
|
13583
|
+
default:
|
|
13584
|
+
return "system";
|
|
13585
|
+
}
|
|
13586
|
+
}
|
|
13587
|
+
function dataString(data, key) {
|
|
13588
|
+
const v = data?.[key];
|
|
13589
|
+
return typeof v === "string" && v.trim().length > 0 ? v.trim() : null;
|
|
13590
|
+
}
|
|
13591
|
+
var CONTROL_MARKUP_RE = /<next_action\b[^>]*(?:\/>|>[\s\S]*?<\/next_action>)/gi;
|
|
13592
|
+
function stripMissionControlMarkup(text) {
|
|
13593
|
+
return text.replace(CONTROL_MARKUP_RE, "").trim();
|
|
13594
|
+
}
|
|
13595
|
+
function missionEventSummary(event) {
|
|
13596
|
+
return stripMissionControlMarkup(rawMissionEventSummary(event));
|
|
13597
|
+
}
|
|
13598
|
+
function rawMissionEventSummary(event) {
|
|
13599
|
+
const d = event.data ?? null;
|
|
13600
|
+
switch (event.type) {
|
|
13601
|
+
case "worker.spawned":
|
|
13602
|
+
return dataString(d, "goal") ?? "Task spawned";
|
|
13603
|
+
case "worker.complete":
|
|
13604
|
+
return dataString(d, "result") ?? "Worker complete";
|
|
13605
|
+
case "iteration.summary":
|
|
13606
|
+
return dataString(d, "summary") ?? "";
|
|
13607
|
+
case "mission.evaluation.end": {
|
|
13608
|
+
const result = dataString(d, "result");
|
|
13609
|
+
const feedback = dataString(d, "feedback") ?? dataString(d, "explanation");
|
|
13610
|
+
if (result && feedback) return `${result} \u2014 ${feedback}`;
|
|
13611
|
+
return result ?? feedback ?? "Evaluation finished";
|
|
13612
|
+
}
|
|
13613
|
+
case "task.blocked":
|
|
13614
|
+
return dataString(d, "reason") ?? "Task blocked";
|
|
13615
|
+
case "task.failed":
|
|
13616
|
+
return "Task failed";
|
|
13617
|
+
default: {
|
|
13618
|
+
const text = dataString(d, "summary") ?? dataString(d, "text") ?? dataString(d, "message") ?? dataString(d, "reason");
|
|
13619
|
+
if (text) return text;
|
|
13620
|
+
if (!d) return "";
|
|
13621
|
+
try {
|
|
13622
|
+
return truncate4(JSON.stringify(d), 160);
|
|
13623
|
+
} catch {
|
|
13624
|
+
return "";
|
|
13625
|
+
}
|
|
13626
|
+
}
|
|
13627
|
+
}
|
|
13628
|
+
}
|
|
13629
|
+
function missionEventTaskId(event, sessions) {
|
|
13630
|
+
return dataString(event.data ?? null, "task_id") ?? sessions[event.sessionId]?.taskId ?? null;
|
|
13631
|
+
}
|
|
13632
|
+
function missionEventActorLabel(event, sessions) {
|
|
13633
|
+
const meta = sessions[event.sessionId];
|
|
13634
|
+
if (!meta) return event.sessionId.slice(0, 8);
|
|
13635
|
+
if (meta.kind === "coordinator") return "orchestrator";
|
|
13636
|
+
return meta.agentDefName ?? "worker";
|
|
13637
|
+
}
|
|
13638
|
+
function missionTaskBlocks(tasks) {
|
|
13639
|
+
const blocks = {};
|
|
13640
|
+
for (const t of tasks) {
|
|
13641
|
+
for (const parent of t.parentIds) {
|
|
13642
|
+
(blocks[parent] ?? (blocks[parent] = [])).push(t.id);
|
|
13643
|
+
}
|
|
13644
|
+
}
|
|
13645
|
+
return blocks;
|
|
13646
|
+
}
|
|
13647
|
+
function missionTaskTitle(goal, max = 80) {
|
|
13648
|
+
const line = goal.split("\n").find((l) => l.trim().length > 0)?.trim() ?? goal.trim();
|
|
13649
|
+
return truncate4(line.replace(/\s+/g, " "), max);
|
|
13650
|
+
}
|
|
13651
|
+
var RAIL_GROUP_DEFS = [
|
|
13652
|
+
{ key: "running", label: "Running", match: (s) => s === "running" },
|
|
13653
|
+
{ key: "blocked", label: "Blocked", match: (s) => s === "blocked" },
|
|
13654
|
+
{
|
|
13655
|
+
key: "queued",
|
|
13656
|
+
label: "Queued",
|
|
13657
|
+
match: (s) => s === "ready" || s === "todo"
|
|
13658
|
+
},
|
|
13659
|
+
{ key: "done", label: "Done", match: (s) => s === "done" },
|
|
13660
|
+
{
|
|
13661
|
+
key: "failed",
|
|
13662
|
+
label: "Failed / cancelled",
|
|
13663
|
+
match: (s) => s === "failed" || s === "cancelled"
|
|
13664
|
+
}
|
|
13665
|
+
];
|
|
13666
|
+
function missionTaskRailGroups(tasks) {
|
|
13667
|
+
const grouped = /* @__PURE__ */ new Set();
|
|
13668
|
+
const groups = RAIL_GROUP_DEFS.map((def) => ({
|
|
13669
|
+
key: def.key,
|
|
13670
|
+
label: def.label,
|
|
13671
|
+
tasks: tasks.filter((t) => {
|
|
13672
|
+
const hit = def.match(t.status);
|
|
13673
|
+
if (hit) grouped.add(t.id);
|
|
13674
|
+
return hit;
|
|
13675
|
+
})
|
|
13676
|
+
}));
|
|
13677
|
+
const stray = tasks.filter((t) => !grouped.has(t.id));
|
|
13678
|
+
if (stray.length > 0) {
|
|
13679
|
+
const queued = groups.find((g) => g.key === "queued");
|
|
13680
|
+
if (queued) queued.tasks.push(...stray);
|
|
13681
|
+
}
|
|
13682
|
+
return groups.filter((g) => g.tasks.length > 0);
|
|
13683
|
+
}
|
|
13684
|
+
var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
|
|
13685
|
+
function defaultSelectedMissionTaskId(tasks) {
|
|
13686
|
+
if (tasks.length === 0) return null;
|
|
13687
|
+
const ordered = missionTaskRailGroups(tasks).flatMap((g) => g.tasks);
|
|
13688
|
+
const firstLive = ordered.find(
|
|
13689
|
+
(t) => !TERMINAL_TASK_STATUSES.has(t.status)
|
|
13690
|
+
);
|
|
13691
|
+
return (firstLive ?? ordered[0] ?? tasks[0]).id;
|
|
13692
|
+
}
|
|
13693
|
+
function mergeMissionEvents(existing, incoming) {
|
|
13694
|
+
if (incoming.length === 0) return existing;
|
|
13695
|
+
const byId = /* @__PURE__ */ new Map();
|
|
13696
|
+
for (const e of existing) byId.set(e.id, e);
|
|
13697
|
+
for (const e of incoming) byId.set(e.id, e);
|
|
13698
|
+
return [...byId.values()].sort((a, b) => a.id - b.id);
|
|
13699
|
+
}
|
|
13700
|
+
function missionTaskStatusDotClass(status) {
|
|
13701
|
+
switch (status) {
|
|
13702
|
+
case "running":
|
|
13703
|
+
return "bg-primary";
|
|
13704
|
+
case "blocked":
|
|
13705
|
+
return "bg-amber-500";
|
|
13706
|
+
case "done":
|
|
13707
|
+
return "bg-emerald-500";
|
|
13708
|
+
case "failed":
|
|
13709
|
+
return "bg-destructive";
|
|
13710
|
+
case "cancelled":
|
|
13711
|
+
return "bg-muted-foreground";
|
|
13712
|
+
default:
|
|
13713
|
+
return "bg-foreground/30";
|
|
13714
|
+
}
|
|
13715
|
+
}
|
|
13716
|
+
function missionWorkerTaskCounts(worker, tasks) {
|
|
13717
|
+
if (worker.kind !== "task") return null;
|
|
13718
|
+
const mine = tasks.filter((t) => t.agentDefName === worker.agentDefName);
|
|
13719
|
+
return {
|
|
13720
|
+
completed: mine.filter((t) => t.status === "done").length,
|
|
13721
|
+
inFlight: mine.filter(
|
|
13722
|
+
(t) => t.status === "running" || t.status === "blocked"
|
|
13723
|
+
).length
|
|
13724
|
+
};
|
|
13725
|
+
}
|
|
13726
|
+
function formatMissionTimestamp(iso) {
|
|
13727
|
+
if (!iso) return "";
|
|
13728
|
+
const parsed = new Date(iso);
|
|
13729
|
+
if (Number.isNaN(parsed.getTime())) return iso;
|
|
13730
|
+
return parsed.toLocaleTimeString();
|
|
13731
|
+
}
|
|
13732
|
+
|
|
13733
|
+
// src/runtime/reducer.ts
|
|
13734
|
+
var EMPTY_TOKEN_USAGE = {
|
|
13735
|
+
inputTokens: 0,
|
|
13736
|
+
outputTokens: 0,
|
|
13737
|
+
reasoningTokens: 0,
|
|
13738
|
+
cachedInputTokens: 0,
|
|
13739
|
+
totalTokens: 0,
|
|
13740
|
+
contextWindow: 0,
|
|
13741
|
+
model: ""
|
|
13742
|
+
};
|
|
13743
|
+
function createInitialAgentChatState(options = {}) {
|
|
13744
|
+
return {
|
|
13745
|
+
messages: [],
|
|
13746
|
+
isRunning: false,
|
|
13747
|
+
isLoadingHistory: options.isLoadingHistory ?? false,
|
|
13748
|
+
tokenUsage: EMPTY_TOKEN_USAGE,
|
|
13749
|
+
retryIndicator: null,
|
|
13750
|
+
lastEventId: 0,
|
|
13751
|
+
sessionDone: false,
|
|
13752
|
+
hadDeltas: false,
|
|
13753
|
+
terminal: false,
|
|
13754
|
+
stopped: false,
|
|
13755
|
+
workspaceRefreshKey: 0,
|
|
13756
|
+
browser: null,
|
|
13757
|
+
browserTabs: [],
|
|
13758
|
+
viewMode: options.viewMode ?? "simple",
|
|
13759
|
+
researchSources: [],
|
|
13760
|
+
deviceWait: null
|
|
13761
|
+
};
|
|
13762
|
+
}
|
|
13763
|
+
function applyAgentChatEvent(state, event) {
|
|
13764
|
+
let nextState = {
|
|
13765
|
+
...state,
|
|
13766
|
+
isLoadingHistory: false,
|
|
13767
|
+
lastEventId: Math.max(state.lastEventId, event.eventId),
|
|
13768
|
+
sessionDone: state.sessionDone || event.type === "session.done"
|
|
13769
|
+
};
|
|
13770
|
+
nextState = applyRetryIndicator(nextState, event);
|
|
13771
|
+
if (state.stopped && isPostTerminalLiveEvent(event.type)) {
|
|
13772
|
+
return nextState;
|
|
13773
|
+
}
|
|
13774
|
+
switch (event.type) {
|
|
13775
|
+
case "user.message":
|
|
13776
|
+
// A project coordinator's follow-up to its thread: shown as the thread reads it, its header saying whose it is.
|
|
13777
|
+
case "coordinator.message":
|
|
13778
|
+
return withMessages(
|
|
13779
|
+
{ ...nextState, terminal: false, stopped: false, isRunning: true },
|
|
13780
|
+
applyUserMessage(nextState.messages, event.eventId, event.data)
|
|
13781
|
+
);
|
|
13782
|
+
case "skill.invoked":
|
|
13092
13783
|
return withMessages(nextState, [
|
|
13093
13784
|
...nextState.messages,
|
|
13094
13785
|
{
|
|
@@ -13160,23 +13851,79 @@ function applyAgentChatEvent(state, event) {
|
|
|
13160
13851
|
}
|
|
13161
13852
|
return withMessages(nextState, [...nextState.messages, artifactMessage]);
|
|
13162
13853
|
}
|
|
13163
|
-
case "browser.provisioned":
|
|
13164
|
-
|
|
13854
|
+
case "browser.provisioned": {
|
|
13855
|
+
const tab = computerTab(event);
|
|
13856
|
+
if (tab === null) {
|
|
13857
|
+
return applyBrowserEvent(nextState, event, {
|
|
13858
|
+
status: "live",
|
|
13859
|
+
controlOwner: null
|
|
13860
|
+
});
|
|
13861
|
+
}
|
|
13862
|
+
const browserTabs = [...nextState.browserTabs.filter((open) => open !== tab), tab];
|
|
13863
|
+
if (nextState.browserTabs.length > 0) {
|
|
13864
|
+
const there = nextState.browser?.computer === true && nextState.browser.status !== "unavailable";
|
|
13865
|
+
return {
|
|
13866
|
+
...nextState,
|
|
13867
|
+
browserTabs,
|
|
13868
|
+
browser: there ? nextState.browser : { status: "live", controlOwner: null, computer: true }
|
|
13869
|
+
};
|
|
13870
|
+
}
|
|
13871
|
+
return applyBrowserEvent({ ...nextState, browserTabs }, event, {
|
|
13165
13872
|
status: "live",
|
|
13166
|
-
controlOwner: null
|
|
13873
|
+
controlOwner: null,
|
|
13874
|
+
computer: true
|
|
13167
13875
|
});
|
|
13876
|
+
}
|
|
13877
|
+
case "browser.unavailable": {
|
|
13878
|
+
const tab = computerTab(event);
|
|
13879
|
+
const browserTabs = tab === null ? [] : nextState.browserTabs.filter((open) => open !== tab);
|
|
13880
|
+
if (browserTabs.length > 0) return { ...nextState, browserTabs };
|
|
13881
|
+
const none = {
|
|
13882
|
+
...nextState,
|
|
13883
|
+
browserTabs,
|
|
13884
|
+
browser: { status: "unavailable", controlOwner: null, computer: true }
|
|
13885
|
+
};
|
|
13886
|
+
if (saidLastOfBrowser(nextState.messages) === NO_BROWSER) return none;
|
|
13887
|
+
return withMessages(none, [...none.messages, browserMarker(event)]);
|
|
13888
|
+
}
|
|
13889
|
+
// A take-over on the user's computer is told as the cloud's is: the browser stays the computer's.
|
|
13168
13890
|
case "browser.control_granted":
|
|
13169
13891
|
return applyBrowserEvent(nextState, event, {
|
|
13170
13892
|
status: "user-control",
|
|
13171
|
-
controlOwner: stringValue2(event.data.owner_user_id) || null
|
|
13893
|
+
controlOwner: stringValue2(event.data.owner_user_id) || null,
|
|
13894
|
+
...onComputer(event)
|
|
13172
13895
|
});
|
|
13173
13896
|
case "browser.control_returned":
|
|
13174
13897
|
return applyBrowserEvent(nextState, event, {
|
|
13175
13898
|
status: "live",
|
|
13176
|
-
controlOwner: null
|
|
13899
|
+
controlOwner: null,
|
|
13900
|
+
...onComputer(event)
|
|
13177
13901
|
});
|
|
13178
|
-
case "browser.destroyed":
|
|
13179
|
-
|
|
13902
|
+
case "browser.destroyed": {
|
|
13903
|
+
const tab = computerTab(event);
|
|
13904
|
+
const browserTabs = tab === null ? [] : nextState.browserTabs.filter((open) => open !== tab);
|
|
13905
|
+
if (browserTabs.length > 0) return { ...nextState, browserTabs };
|
|
13906
|
+
return applyBrowserEvent({ ...nextState, browserTabs }, event, null);
|
|
13907
|
+
}
|
|
13908
|
+
case "device.waiting":
|
|
13909
|
+
return {
|
|
13910
|
+
...nextState,
|
|
13911
|
+
deviceWait: {
|
|
13912
|
+
deviceId: stringValue2(event.data.device_id),
|
|
13913
|
+
deviceName: stringValue2(event.data.device_name),
|
|
13914
|
+
reason: stringValue2(event.data.reason) || "offline",
|
|
13915
|
+
folder: stringValue2(event.data.folder)
|
|
13916
|
+
}
|
|
13917
|
+
};
|
|
13918
|
+
case "device.resumed":
|
|
13919
|
+
return { ...nextState, deviceWait: null };
|
|
13920
|
+
case "worker.spawned":
|
|
13921
|
+
return withMessages(nextState, applyWorkerSpawned(nextState.messages, event));
|
|
13922
|
+
case "worker.complete":
|
|
13923
|
+
case "worker.failed":
|
|
13924
|
+
return withMessages(nextState, applyWorkerReport(nextState.messages, event));
|
|
13925
|
+
case "thread.proposed":
|
|
13926
|
+
return withMessages(nextState, [...nextState.messages, proposalMessage(event)]);
|
|
13180
13927
|
case "llm.delta":
|
|
13181
13928
|
return applyLlmDelta(nextState, event);
|
|
13182
13929
|
case "llm.response":
|
|
@@ -13198,7 +13945,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
13198
13945
|
return collectResearchSource(withResult, toolName, event.data);
|
|
13199
13946
|
}
|
|
13200
13947
|
case "harness.wake":
|
|
13201
|
-
return { ...nextState, terminal: false, isRunning: true };
|
|
13948
|
+
return { ...nextState, terminal: false, isRunning: true, deviceWait: null };
|
|
13202
13949
|
case "llm.request":
|
|
13203
13950
|
return {
|
|
13204
13951
|
...nextState,
|
|
@@ -13227,7 +13974,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
13227
13974
|
if (event.data.strategy === "clear") {
|
|
13228
13975
|
return {
|
|
13229
13976
|
...nextState,
|
|
13230
|
-
messages:
|
|
13977
|
+
messages: typedBehindTheClear(nextState.messages, event.data.answers),
|
|
13231
13978
|
tokenUsage: EMPTY_TOKEN_USAGE
|
|
13232
13979
|
};
|
|
13233
13980
|
}
|
|
@@ -13319,6 +14066,17 @@ function applyRetryIndicator(state, event) {
|
|
|
13319
14066
|
return state;
|
|
13320
14067
|
}
|
|
13321
14068
|
}
|
|
14069
|
+
function typedBehindTheClear(messages, answers) {
|
|
14070
|
+
if (typeof answers !== "number") return [];
|
|
14071
|
+
let first = messages.length;
|
|
14072
|
+
while (first > 0) {
|
|
14073
|
+
const message = messages[first - 1];
|
|
14074
|
+
const typedAt = /^evt-(\d+)$/.exec(message.id);
|
|
14075
|
+
if (message.role !== "user" || !typedAt || Number(typedAt[1]) <= answers) break;
|
|
14076
|
+
first -= 1;
|
|
14077
|
+
}
|
|
14078
|
+
return messages.slice(first);
|
|
14079
|
+
}
|
|
13322
14080
|
function applyUserMessage(messages, eventId, data) {
|
|
13323
14081
|
const content = stringValue2(data.content);
|
|
13324
14082
|
const images = parseUserMessageImages(data.images);
|
|
@@ -13384,6 +14142,22 @@ function parseUserMessageAttachments(raw) {
|
|
|
13384
14142
|
}
|
|
13385
14143
|
return out.length > 0 ? out : void 0;
|
|
13386
14144
|
}
|
|
14145
|
+
function onComputer(event) {
|
|
14146
|
+
return event.data.computer === true ? { computer: true } : {};
|
|
14147
|
+
}
|
|
14148
|
+
function computerTab(event) {
|
|
14149
|
+
return event.data.computer === true ? stringValue2(event.data.session_id) : null;
|
|
14150
|
+
}
|
|
14151
|
+
var NO_BROWSER = "No supported browser on the chat's computer.";
|
|
14152
|
+
function saidLastOfBrowser(messages) {
|
|
14153
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
14154
|
+
const message = messages[index];
|
|
14155
|
+
if (message.systemKind === "browser_marker" || message.systemKind === "browser_marker_warning") {
|
|
14156
|
+
return message.content;
|
|
14157
|
+
}
|
|
14158
|
+
}
|
|
14159
|
+
return void 0;
|
|
14160
|
+
}
|
|
13387
14161
|
function applyBrowserEvent(state, event, browser) {
|
|
13388
14162
|
return withMessages(
|
|
13389
14163
|
{ ...state, browser },
|
|
@@ -13407,6 +14181,10 @@ function browserMarker(event) {
|
|
|
13407
14181
|
"browser.destroyed": {
|
|
13408
14182
|
content: "Browser closed.",
|
|
13409
14183
|
warning: false
|
|
14184
|
+
},
|
|
14185
|
+
"browser.unavailable": {
|
|
14186
|
+
content: NO_BROWSER,
|
|
14187
|
+
warning: true
|
|
13410
14188
|
}
|
|
13411
14189
|
};
|
|
13412
14190
|
const label = labels[event.type] ?? {
|
|
@@ -13654,6 +14432,67 @@ function applyTurnSummary(state, event) {
|
|
|
13654
14432
|
};
|
|
13655
14433
|
return { ...state, messages };
|
|
13656
14434
|
}
|
|
14435
|
+
function workerMessage(worker) {
|
|
14436
|
+
return {
|
|
14437
|
+
id: `worker-${worker.id}`,
|
|
14438
|
+
role: "system",
|
|
14439
|
+
content: worker.title ?? worker.goal,
|
|
14440
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
14441
|
+
status: "complete",
|
|
14442
|
+
systemKind: "worker",
|
|
14443
|
+
worker
|
|
14444
|
+
};
|
|
14445
|
+
}
|
|
14446
|
+
function applyWorkerSpawned(messages, event) {
|
|
14447
|
+
const id = stringValue2(event.data.worker_id);
|
|
14448
|
+
const proposalId = stringValue2(event.data.proposal_id);
|
|
14449
|
+
const key = stringValue2(event.data.key);
|
|
14450
|
+
const marked = proposalId && key ? messages.map((message) => message.proposal?.proposalId === proposalId ? { ...message, proposal: { ...message.proposal, started: { ...message.proposal.started, [key]: id } } } : message) : messages;
|
|
14451
|
+
if (marked.some((message) => message.worker?.id === id)) return marked;
|
|
14452
|
+
return [...marked, workerMessage({
|
|
14453
|
+
id,
|
|
14454
|
+
title: stringValue2(event.data.title) || null,
|
|
14455
|
+
goal: stringValue2(event.data.goal),
|
|
14456
|
+
state: "working",
|
|
14457
|
+
report: null,
|
|
14458
|
+
files: []
|
|
14459
|
+
})];
|
|
14460
|
+
}
|
|
14461
|
+
function applyWorkerReport(messages, event) {
|
|
14462
|
+
const id = stringValue2(event.data.worker_id);
|
|
14463
|
+
const failed = event.type === "worker.failed";
|
|
14464
|
+
const index = messages.findIndex((message) => message.worker?.id === id);
|
|
14465
|
+
if (index === -1) return messages;
|
|
14466
|
+
const worker = messages[index].worker;
|
|
14467
|
+
const reported = {
|
|
14468
|
+
...worker,
|
|
14469
|
+
state: failed ? "failed" : "reported",
|
|
14470
|
+
// A mission worker's result can carry the loop's control markup, which never reaches the UI.
|
|
14471
|
+
report: stripMissionControlMarkup(stringValue2(failed ? event.data.error : event.data.result)) || null,
|
|
14472
|
+
// A card lists files, as a thread's row does: not the URLs and commands a turn names.
|
|
14473
|
+
files: failed ? worker.files : parseTurnArtifacts(event.data.files).filter((file) => file.kind === "file" || file.kind === "artifact")
|
|
14474
|
+
};
|
|
14475
|
+
const next = [...messages];
|
|
14476
|
+
next[index] = { ...next[index], worker: reported };
|
|
14477
|
+
return next;
|
|
14478
|
+
}
|
|
14479
|
+
function proposalMessage(event) {
|
|
14480
|
+
const threads = (Array.isArray(event.data.threads) ? event.data.threads : []).filter((thread) => !!thread && typeof thread === "object").map((thread) => ({
|
|
14481
|
+
key: stringValue2(thread.key),
|
|
14482
|
+
title: stringValue2(thread.title),
|
|
14483
|
+
goal: stringValue2(thread.goal),
|
|
14484
|
+
where: thread.where === "device" ? "device" : "cloud"
|
|
14485
|
+
}));
|
|
14486
|
+
return {
|
|
14487
|
+
id: `proposal-${stringValue2(event.data.proposal_id)}`,
|
|
14488
|
+
role: "system",
|
|
14489
|
+
content: threads.map((thread) => thread.title).join(", "),
|
|
14490
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
14491
|
+
status: "complete",
|
|
14492
|
+
systemKind: "thread_proposal",
|
|
14493
|
+
proposal: { proposalId: stringValue2(event.data.proposal_id), threads, started: {} }
|
|
14494
|
+
};
|
|
14495
|
+
}
|
|
13657
14496
|
function parseTurnArtifacts(raw) {
|
|
13658
14497
|
if (!Array.isArray(raw)) return [];
|
|
13659
14498
|
const out = [];
|
|
@@ -13756,7 +14595,7 @@ function applyTerminalEvent(state, event) {
|
|
|
13756
14595
|
status: event.type === "session.fail" ? "error" : "complete",
|
|
13757
14596
|
errorInfo: errorInfo ?? doneMsg.errorInfo
|
|
13758
14597
|
};
|
|
13759
|
-
} else if (
|
|
14598
|
+
} else if (errorInfo) {
|
|
13760
14599
|
messages.push({
|
|
13761
14600
|
id: `error-${event.eventId}`,
|
|
13762
14601
|
role: "system",
|
|
@@ -13775,7 +14614,7 @@ function applyTerminalEvent(state, event) {
|
|
|
13775
14614
|
};
|
|
13776
14615
|
}
|
|
13777
14616
|
function buildErrorInfo(event) {
|
|
13778
|
-
if (event.type !== "session.fail" || typeof event.data.error_category !== "string") {
|
|
14617
|
+
if (event.type !== "session.fail" && event.type !== "session.pause" || typeof event.data.error_category !== "string") {
|
|
13779
14618
|
return void 0;
|
|
13780
14619
|
}
|
|
13781
14620
|
const detail = stringValue2(event.data.error_detail) || stringValue2(event.data.error);
|
|
@@ -14523,7 +15362,8 @@ function useAgentChatRuntime({
|
|
|
14523
15362
|
...prev,
|
|
14524
15363
|
browser: browserState ? {
|
|
14525
15364
|
status: browserState.status,
|
|
14526
|
-
controlOwner: browserState.controlOwner ?? null
|
|
15365
|
+
controlOwner: browserState.controlOwner ?? null,
|
|
15366
|
+
...browserState.computer ? { computer: true } : {}
|
|
14527
15367
|
} : null
|
|
14528
15368
|
}));
|
|
14529
15369
|
}).catch(() => void 0);
|
|
@@ -17018,17 +17858,21 @@ function saveDoc(adapter, sessionId, doc) {
|
|
|
17018
17858
|
file,
|
|
17019
17859
|
directory: CANVAS_DIR
|
|
17020
17860
|
});
|
|
17861
|
+
return true;
|
|
17021
17862
|
} catch {
|
|
17863
|
+
return false;
|
|
17022
17864
|
}
|
|
17023
17865
|
})();
|
|
17024
17866
|
inFlightSaves.set(sessionId, done);
|
|
17025
|
-
return done.then(() => {
|
|
17867
|
+
return done.then((saved) => {
|
|
17026
17868
|
if (inFlightSaves.get(sessionId) === done) {
|
|
17027
17869
|
inFlightSaves.delete(sessionId);
|
|
17028
17870
|
}
|
|
17871
|
+
return saved;
|
|
17029
17872
|
});
|
|
17030
17873
|
}
|
|
17031
17874
|
function useDebouncedSave(adapter, sessionId, doc, delayMs = SAVE_DEBOUNCE_MS) {
|
|
17875
|
+
const [unsaved, setUnsaved] = useState(false);
|
|
17032
17876
|
const latest = useRef(doc);
|
|
17033
17877
|
latest.current = doc;
|
|
17034
17878
|
const dirty = useRef(false);
|
|
@@ -17040,7 +17884,7 @@ function useDebouncedSave(adapter, sessionId, doc, delayMs = SAVE_DEBOUNCE_MS) {
|
|
|
17040
17884
|
}
|
|
17041
17885
|
dirty.current = true;
|
|
17042
17886
|
const timer = setTimeout(() => {
|
|
17043
|
-
void saveDoc(adapter, sessionId, latest.current);
|
|
17887
|
+
void saveDoc(adapter, sessionId, latest.current).then((saved) => setUnsaved(!saved));
|
|
17044
17888
|
}, delayMs);
|
|
17045
17889
|
return () => clearTimeout(timer);
|
|
17046
17890
|
}, [adapter, sessionId, doc, delayMs]);
|
|
@@ -17050,6 +17894,7 @@ function useDebouncedSave(adapter, sessionId, doc, delayMs = SAVE_DEBOUNCE_MS) {
|
|
|
17050
17894
|
void saveDoc(adapter, sessionId, latest.current);
|
|
17051
17895
|
};
|
|
17052
17896
|
}, [adapter, sessionId]);
|
|
17897
|
+
return unsaved;
|
|
17053
17898
|
}
|
|
17054
17899
|
function shouldReloadCanvas(previous, next, opts = {}) {
|
|
17055
17900
|
if (!next) return false;
|
|
@@ -17358,7 +18203,7 @@ function WhiteboardSurface({
|
|
|
17358
18203
|
return next;
|
|
17359
18204
|
});
|
|
17360
18205
|
}, [runtime.messages, canvasReady, resolveDraw]);
|
|
17361
|
-
useDebouncedSave(adapter, canvasReady ? sessionId : null, doc);
|
|
18206
|
+
const unsaved = useDebouncedSave(adapter, canvasReady ? sessionId : null, doc);
|
|
17362
18207
|
const hasAnswer = useMemo(
|
|
17363
18208
|
() => runtime.messages.some((m) => m.role === "assistant"),
|
|
17364
18209
|
[runtime.messages]
|
|
@@ -17971,6 +18816,7 @@ function WhiteboardSurface({
|
|
|
17971
18816
|
/* @__PURE__ */ jsx(Spinner, { className: "size-4 shrink-0" }),
|
|
17972
18817
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: progress ?? (askMode === "deep" ? "Working it out\u2026" : "Thinking\u2026") })
|
|
17973
18818
|
] }) }) }) : null,
|
|
18819
|
+
unsaved ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute right-2 top-2 z-10", children: /* @__PURE__ */ jsx("span", { role: "status", className: "rounded-full border bg-background px-3 py-1 text-xs text-muted-foreground shadow-sm", children: "Your last change wasn't saved." }) }) : null,
|
|
17974
18820
|
restoringVisible ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center bg-black/10", children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-3 rounded-full border bg-background px-6 py-3 text-sm font-medium text-muted-foreground shadow-md", children: [
|
|
17975
18821
|
/* @__PURE__ */ jsx(Spinner, { className: "size-5" }),
|
|
17976
18822
|
"Restoring board\u2026"
|
|
@@ -18709,7 +19555,38 @@ function FileTreeFile({
|
|
|
18709
19555
|
}
|
|
18710
19556
|
);
|
|
18711
19557
|
}
|
|
19558
|
+
var NONE = {};
|
|
19559
|
+
var chats = /* @__PURE__ */ new Map();
|
|
19560
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
19561
|
+
function changed() {
|
|
19562
|
+
for (const listener of listeners) listener();
|
|
19563
|
+
}
|
|
19564
|
+
function changeChatFiles(chat, changes) {
|
|
19565
|
+
chats.set(chat, { ...chats.get(chat), ...changes });
|
|
19566
|
+
changed();
|
|
19567
|
+
}
|
|
19568
|
+
function leaveChatFiles(chat) {
|
|
19569
|
+
const was = chats.get(chat);
|
|
19570
|
+
if (!was) return;
|
|
19571
|
+
const { entries: _tree, truncated: _cut, ...kept } = was;
|
|
19572
|
+
chats.set(chat, was.deleting ? kept : { ...kept, deleteTarget: null });
|
|
19573
|
+
changed();
|
|
19574
|
+
}
|
|
19575
|
+
function forgetChatFiles() {
|
|
19576
|
+
chats.clear();
|
|
19577
|
+
changed();
|
|
19578
|
+
}
|
|
19579
|
+
function subscribe2(listener) {
|
|
19580
|
+
listeners.add(listener);
|
|
19581
|
+
return () => {
|
|
19582
|
+
listeners.delete(listener);
|
|
19583
|
+
};
|
|
19584
|
+
}
|
|
19585
|
+
function useChatFiles(chat) {
|
|
19586
|
+
return useSyncExternalStore(subscribe2, () => chat === null ? NONE : chats.get(chat) ?? NONE);
|
|
19587
|
+
}
|
|
18712
19588
|
var SKELETON_WIDTHS2 = [75, 60, 90, 65, 80, 70, 85, 55];
|
|
19589
|
+
var NO_ENTRIES = [];
|
|
18713
19590
|
function collectExpandedPaths(entries, depth = 0) {
|
|
18714
19591
|
const paths = [];
|
|
18715
19592
|
for (const entry of entries) {
|
|
@@ -18823,43 +19700,69 @@ function WorkspacePanel({
|
|
|
18823
19700
|
disabled = false
|
|
18824
19701
|
}) {
|
|
18825
19702
|
const fileInputRef = useRef(null);
|
|
18826
|
-
const
|
|
18827
|
-
|
|
18828
|
-
|
|
18829
|
-
|
|
18830
|
-
|
|
18831
|
-
|
|
19703
|
+
const {
|
|
19704
|
+
entries = NO_ENTRIES,
|
|
19705
|
+
truncated = false,
|
|
19706
|
+
loading = false,
|
|
19707
|
+
error = null,
|
|
19708
|
+
waiting = null,
|
|
19709
|
+
notice = null,
|
|
19710
|
+
uploading = false,
|
|
19711
|
+
deleteTarget = null,
|
|
19712
|
+
deleting = false
|
|
19713
|
+
} = useChatFiles(sessionId);
|
|
18832
19714
|
const [expandedPaths, setExpandedPaths] = useState(/* @__PURE__ */ new Set());
|
|
18833
19715
|
const sessionIdRef = useRef(sessionId);
|
|
19716
|
+
const mountedRef = useRef(true);
|
|
19717
|
+
const readingRef = useRef(null);
|
|
18834
19718
|
sessionIdRef.current = sessionId;
|
|
19719
|
+
const stopReading = useCallback(() => {
|
|
19720
|
+
const was = readingRef.current;
|
|
19721
|
+
readingRef.current = null;
|
|
19722
|
+
if (!was) return;
|
|
19723
|
+
was.controller.abort();
|
|
19724
|
+
changeChatFiles(was.chat, { loading: false, waiting: null });
|
|
19725
|
+
}, []);
|
|
19726
|
+
useEffect(() => {
|
|
19727
|
+
mountedRef.current = true;
|
|
19728
|
+
return () => {
|
|
19729
|
+
mountedRef.current = false;
|
|
19730
|
+
stopReading();
|
|
19731
|
+
};
|
|
19732
|
+
}, [stopReading]);
|
|
19733
|
+
useEffect(() => () => {
|
|
19734
|
+
if (sessionId) leaveChatFiles(sessionId);
|
|
19735
|
+
}, [sessionId]);
|
|
18835
19736
|
const fetchTree = useCallback(async () => {
|
|
18836
|
-
if (!sessionId)
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18844
|
-
setTreeLoading(true);
|
|
18845
|
-
setTreeError(null);
|
|
19737
|
+
if (!mountedRef.current || sessionIdRef.current !== sessionId) return;
|
|
19738
|
+
stopReading();
|
|
19739
|
+
if (!sessionId) return;
|
|
19740
|
+
const chat = sessionId;
|
|
19741
|
+
const reading = { chat, controller: new AbortController() };
|
|
19742
|
+
readingRef.current = reading;
|
|
19743
|
+
const current = () => readingRef.current === reading;
|
|
19744
|
+
changeChatFiles(chat, { loading: true, waiting: null, error: null });
|
|
18846
19745
|
try {
|
|
18847
19746
|
const tree = await adapter.getWorkspaceTree({
|
|
18848
|
-
sessionId:
|
|
19747
|
+
sessionId: chat,
|
|
19748
|
+
signal: reading.controller.signal,
|
|
19749
|
+
onWaiting: (said) => {
|
|
19750
|
+
if (current()) changeChatFiles(chat, { waiting: said });
|
|
19751
|
+
}
|
|
18849
19752
|
});
|
|
18850
|
-
if (
|
|
18851
|
-
|
|
19753
|
+
if (!current()) return;
|
|
19754
|
+
changeChatFiles(chat, { entries: tree.entries, truncated: tree.truncated });
|
|
18852
19755
|
setExpandedPaths(new Set(collectExpandedPaths(tree.entries)));
|
|
18853
|
-
} catch (
|
|
18854
|
-
if (
|
|
18855
|
-
|
|
18856
|
-
setTreeError(error.message);
|
|
19756
|
+
} catch (error2) {
|
|
19757
|
+
if (!current()) return;
|
|
19758
|
+
changeChatFiles(chat, { entries: [], error: error2.message });
|
|
18857
19759
|
} finally {
|
|
18858
|
-
if (
|
|
18859
|
-
|
|
19760
|
+
if (current()) {
|
|
19761
|
+
readingRef.current = null;
|
|
19762
|
+
changeChatFiles(chat, { loading: false, waiting: null });
|
|
18860
19763
|
}
|
|
18861
19764
|
}
|
|
18862
|
-
}, [adapter, sessionId]);
|
|
19765
|
+
}, [adapter, sessionId, stopReading]);
|
|
18863
19766
|
useEffect(() => {
|
|
18864
19767
|
void fetchTree();
|
|
18865
19768
|
}, [fetchTree]);
|
|
@@ -18902,23 +19805,24 @@ function WorkspacePanel({
|
|
|
18902
19805
|
const handleUpload = useCallback(
|
|
18903
19806
|
async (files) => {
|
|
18904
19807
|
if (disabled || !sessionId || files.length === 0) return;
|
|
18905
|
-
|
|
18906
|
-
|
|
19808
|
+
const chat = sessionId;
|
|
19809
|
+
changeChatFiles(chat, { uploading: true, notice: null });
|
|
18907
19810
|
try {
|
|
18908
19811
|
for (const uploadedFile of Array.from(files)) {
|
|
18909
19812
|
await adapter.uploadWorkspaceFile({
|
|
18910
|
-
sessionId,
|
|
18911
|
-
file: uploadedFile
|
|
19813
|
+
sessionId: chat,
|
|
19814
|
+
file: uploadedFile,
|
|
19815
|
+
onWaiting: (said) => changeChatFiles(chat, { notice: said })
|
|
18912
19816
|
});
|
|
18913
19817
|
}
|
|
18914
|
-
|
|
18915
|
-
files.length === 1 ? `Uploaded ${files[0]?.name ?? "file"}` : `Uploaded ${files.length} files`
|
|
18916
|
-
);
|
|
19818
|
+
changeChatFiles(chat, {
|
|
19819
|
+
notice: files.length === 1 ? `Uploaded ${files[0]?.name ?? "file"}` : `Uploaded ${files.length} files`
|
|
19820
|
+
});
|
|
18917
19821
|
await fetchTree();
|
|
18918
|
-
} catch (
|
|
18919
|
-
|
|
19822
|
+
} catch (error2) {
|
|
19823
|
+
changeChatFiles(chat, { notice: error2.message });
|
|
18920
19824
|
} finally {
|
|
18921
|
-
|
|
19825
|
+
changeChatFiles(chat, { uploading: false });
|
|
18922
19826
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
18923
19827
|
}
|
|
18924
19828
|
},
|
|
@@ -18927,17 +19831,23 @@ function WorkspacePanel({
|
|
|
18927
19831
|
const handleDelete = useCallback(
|
|
18928
19832
|
async (path) => {
|
|
18929
19833
|
if (disabled || !sessionId) return;
|
|
19834
|
+
const chat = sessionId;
|
|
19835
|
+
changeChatFiles(chat, { deleting: true });
|
|
18930
19836
|
try {
|
|
18931
|
-
await adapter.deleteWorkspaceFile({
|
|
18932
|
-
|
|
19837
|
+
await adapter.deleteWorkspaceFile({
|
|
19838
|
+
sessionId: chat,
|
|
19839
|
+
path,
|
|
19840
|
+
onWaiting: (said) => changeChatFiles(chat, { notice: said })
|
|
19841
|
+
});
|
|
19842
|
+
if (mountedRef.current && sessionIdRef.current === chat && selectedPath === path) {
|
|
18933
19843
|
onSelectedPathChange(null);
|
|
18934
19844
|
}
|
|
18935
|
-
|
|
19845
|
+
changeChatFiles(chat, { notice: `Deleted ${path.split("/").pop() ?? path}` });
|
|
18936
19846
|
await fetchTree();
|
|
18937
|
-
} catch (
|
|
18938
|
-
|
|
19847
|
+
} catch (error2) {
|
|
19848
|
+
changeChatFiles(chat, { notice: error2.message });
|
|
18939
19849
|
} finally {
|
|
18940
|
-
|
|
19850
|
+
changeChatFiles(chat, { deleteTarget: null, deleting: false });
|
|
18941
19851
|
}
|
|
18942
19852
|
},
|
|
18943
19853
|
[
|
|
@@ -18995,12 +19905,12 @@ function WorkspacePanel({
|
|
|
18995
19905
|
variant: "ghost",
|
|
18996
19906
|
size: "icon-sm",
|
|
18997
19907
|
onClick: () => void fetchTree(),
|
|
18998
|
-
disabled: !sessionId ||
|
|
19908
|
+
disabled: !sessionId || loading,
|
|
18999
19909
|
"aria-label": "Refresh workspace",
|
|
19000
19910
|
children: /* @__PURE__ */ jsx(
|
|
19001
19911
|
RefreshCwIcon,
|
|
19002
19912
|
{
|
|
19003
|
-
className: cn("size-4",
|
|
19913
|
+
className: cn("size-4", loading && "animate-spin")
|
|
19004
19914
|
}
|
|
19005
19915
|
)
|
|
19006
19916
|
}
|
|
@@ -19008,9 +19918,26 @@ function WorkspacePanel({
|
|
|
19008
19918
|
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Refresh" })
|
|
19009
19919
|
] })
|
|
19010
19920
|
] }),
|
|
19011
|
-
notice && /* @__PURE__ */ jsx(
|
|
19921
|
+
notice && /* @__PURE__ */ jsx(
|
|
19922
|
+
"div",
|
|
19923
|
+
{
|
|
19924
|
+
"data-testid": "workspace-notice",
|
|
19925
|
+
className: "border-b border-line px-3 py-2 text-xs text-muted-foreground",
|
|
19926
|
+
children: notice
|
|
19927
|
+
}
|
|
19928
|
+
),
|
|
19929
|
+
truncated && entries.length > 0 && /* @__PURE__ */ jsx("div", { className: "border-b border-line px-3 py-2 text-xs text-muted-foreground", children: "Some files are not shown." }),
|
|
19012
19930
|
/* @__PURE__ */ jsx(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxs("div", { className: "px-1 py-1", children: [
|
|
19013
|
-
|
|
19931
|
+
waiting && /* @__PURE__ */ jsx(
|
|
19932
|
+
"div",
|
|
19933
|
+
{
|
|
19934
|
+
role: "status",
|
|
19935
|
+
"data-testid": "tree-waiting",
|
|
19936
|
+
className: "px-3 py-2 text-sm text-muted-foreground",
|
|
19937
|
+
children: waiting
|
|
19938
|
+
}
|
|
19939
|
+
),
|
|
19940
|
+
loading && !waiting && entries.length === 0 && /* @__PURE__ */ jsx("div", { className: "space-y-1 p-2", children: Array.from({ length: 8 }).map((_, index) => /* @__PURE__ */ jsx(
|
|
19014
19941
|
Skeleton,
|
|
19015
19942
|
{
|
|
19016
19943
|
className: "h-5 rounded",
|
|
@@ -19020,11 +19947,11 @@ function WorkspacePanel({
|
|
|
19020
19947
|
},
|
|
19021
19948
|
index
|
|
19022
19949
|
)) }),
|
|
19023
|
-
|
|
19950
|
+
error && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 p-3 text-sm text-destructive", children: [
|
|
19024
19951
|
/* @__PURE__ */ jsx(AlertCircleIcon, { className: "mt-0.5 size-4 shrink-0" }),
|
|
19025
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
19952
|
+
/* @__PURE__ */ jsx("span", { children: error })
|
|
19026
19953
|
] }),
|
|
19027
|
-
!
|
|
19954
|
+
!loading && !error && entries.length === 0 && /* @__PURE__ */ jsxs("div", { className: "px-4 py-8 text-center text-sm text-faint", children: [
|
|
19028
19955
|
/* @__PURE__ */ jsx("p", { children: "No workspace files" }),
|
|
19029
19956
|
/* @__PURE__ */ jsxs(
|
|
19030
19957
|
Button,
|
|
@@ -19053,7 +19980,9 @@ function WorkspacePanel({
|
|
|
19053
19980
|
RenderEntries,
|
|
19054
19981
|
{
|
|
19055
19982
|
entries,
|
|
19056
|
-
onDelete:
|
|
19983
|
+
onDelete: (path) => {
|
|
19984
|
+
if (sessionId) changeChatFiles(sessionId, { deleteTarget: path });
|
|
19985
|
+
},
|
|
19057
19986
|
downloadUrlFor: (path) => sessionId ? adapter.getWorkspaceDownloadUrl({ sessionId, path }) : "#"
|
|
19058
19987
|
}
|
|
19059
19988
|
)
|
|
@@ -19067,8 +19996,13 @@ function WorkspacePanel({
|
|
|
19067
19996
|
title: "Delete file?",
|
|
19068
19997
|
description: `This will permanently delete ${deleteTarget?.split("/").pop() ?? "this file"} from the workspace.`,
|
|
19069
19998
|
confirmLabel: "Delete",
|
|
19070
|
-
|
|
19071
|
-
|
|
19999
|
+
loading: deleting,
|
|
20000
|
+
onConfirm: () => {
|
|
20001
|
+
if (deleteTarget) void handleDelete(deleteTarget);
|
|
20002
|
+
},
|
|
20003
|
+
onCancel: () => {
|
|
20004
|
+
if (sessionId) changeChatFiles(sessionId, { deleteTarget: null });
|
|
20005
|
+
}
|
|
19072
20006
|
}
|
|
19073
20007
|
)
|
|
19074
20008
|
]
|
|
@@ -19081,18 +20015,10 @@ function ConfirmDialog2({
|
|
|
19081
20015
|
title,
|
|
19082
20016
|
description,
|
|
19083
20017
|
confirmLabel,
|
|
20018
|
+
loading,
|
|
19084
20019
|
onConfirm,
|
|
19085
20020
|
onCancel
|
|
19086
20021
|
}) {
|
|
19087
|
-
const [loading, setLoading] = useState(false);
|
|
19088
|
-
const handleConfirm = async () => {
|
|
19089
|
-
setLoading(true);
|
|
19090
|
-
try {
|
|
19091
|
-
await onConfirm();
|
|
19092
|
-
} finally {
|
|
19093
|
-
setLoading(false);
|
|
19094
|
-
}
|
|
19095
|
-
};
|
|
19096
20022
|
return /* @__PURE__ */ jsx(
|
|
19097
20023
|
Dialog,
|
|
19098
20024
|
{
|
|
@@ -19112,7 +20038,7 @@ function ConfirmDialog2({
|
|
|
19112
20038
|
{
|
|
19113
20039
|
variant: "destructive",
|
|
19114
20040
|
disabled: loading,
|
|
19115
|
-
onClick:
|
|
20041
|
+
onClick: onConfirm,
|
|
19116
20042
|
children: [
|
|
19117
20043
|
loading && /* @__PURE__ */ jsx(Loader2Icon, { className: "mr-1.5 size-3.5 animate-spin" }),
|
|
19118
20044
|
confirmLabel
|
|
@@ -19126,6 +20052,10 @@ function ConfirmDialog2({
|
|
|
19126
20052
|
}
|
|
19127
20053
|
|
|
19128
20054
|
// src/lib/sessions.ts
|
|
20055
|
+
function sessionComputer(config) {
|
|
20056
|
+
const execution = config?.execution;
|
|
20057
|
+
return execution?.kind === "device" && typeof execution.device_name === "string" ? execution.device_name : null;
|
|
20058
|
+
}
|
|
19129
20059
|
function isScheduledRunSession(session) {
|
|
19130
20060
|
return Boolean(
|
|
19131
20061
|
session?.channel === "scheduled" || session?.config?.scheduled_session_id
|
|
@@ -19186,7 +20116,11 @@ function AgentChat({
|
|
|
19186
20116
|
goalsEnabled = true,
|
|
19187
20117
|
compressEnabled = true,
|
|
19188
20118
|
onOpenIntegrations,
|
|
19189
|
-
onOpenBilling
|
|
20119
|
+
onOpenBilling,
|
|
20120
|
+
composerFooter,
|
|
20121
|
+
firstMessage,
|
|
20122
|
+
onFirstMessageSent,
|
|
20123
|
+
computerBrowser
|
|
19190
20124
|
}) {
|
|
19191
20125
|
const [workspacePath, setWorkspacePath] = useState(null);
|
|
19192
20126
|
const [previewPath, setPreviewPath] = useState(null);
|
|
@@ -19199,6 +20133,9 @@ function AgentChat({
|
|
|
19199
20133
|
sessionId,
|
|
19200
20134
|
onSessionChange
|
|
19201
20135
|
});
|
|
20136
|
+
const sessionConfig = runtime.session?.config;
|
|
20137
|
+
const projectId = sessionConfig?.workstream_role === "coordinator" && typeof sessionConfig.workstream_id === "string" ? sessionConfig.workstream_id : null;
|
|
20138
|
+
const threadRows = useProjectThreads(adapter, projectId);
|
|
19202
20139
|
useEffect(() => {
|
|
19203
20140
|
setOpenPane(null);
|
|
19204
20141
|
setFilesOpen(false);
|
|
@@ -19226,13 +20163,14 @@ function AgentChat({
|
|
|
19226
20163
|
const browserState = runtime.state.browser;
|
|
19227
20164
|
const browserAvailable = browserState !== null && browserState.status !== "closed" && !!sessionId;
|
|
19228
20165
|
const browserVisible = browserAvailable && openPane === "browser";
|
|
20166
|
+
const browserOnComputer = browserState?.computer === true;
|
|
19229
20167
|
const workspaceAvailable = !!sessionId;
|
|
19230
20168
|
const filePreviewVisible = workspaceAvailable && previewPath !== null && openPane === "file";
|
|
19231
20169
|
const rightStackVisible = browserVisible || filePreviewVisible;
|
|
19232
20170
|
const browserPreview = useBrowserPreview({
|
|
19233
20171
|
adapter,
|
|
19234
20172
|
sessionId,
|
|
19235
|
-
enabled: browserAvailable
|
|
20173
|
+
enabled: browserAvailable && !browserOnComputer
|
|
19236
20174
|
});
|
|
19237
20175
|
const browserRunning = browserAvailable;
|
|
19238
20176
|
useEffect(() => {
|
|
@@ -19243,6 +20181,46 @@ function AgentChat({
|
|
|
19243
20181
|
useEffect(() => {
|
|
19244
20182
|
onMessagesChange?.(runtime.messages);
|
|
19245
20183
|
}, [onMessagesChange, runtime.messages]);
|
|
20184
|
+
const firstSent = useRef(null);
|
|
20185
|
+
const first = useRef({ message: firstMessage ?? null, told: onFirstMessageSent });
|
|
20186
|
+
useEffect(() => {
|
|
20187
|
+
first.current = { message: firstMessage ?? null, told: onFirstMessageSent };
|
|
20188
|
+
});
|
|
20189
|
+
const send = runtime.send;
|
|
20190
|
+
useEffect(() => {
|
|
20191
|
+
if (!firstMessage || firstSent.current === firstMessage.id) return;
|
|
20192
|
+
if (sessionId !== null) {
|
|
20193
|
+
firstSent.current = firstMessage.id;
|
|
20194
|
+
first.current.told?.(firstMessage.id, "Another chat opened before this one was made, so nothing was sent.");
|
|
20195
|
+
return;
|
|
20196
|
+
}
|
|
20197
|
+
if (effectiveDisabled) return;
|
|
20198
|
+
let live = true;
|
|
20199
|
+
queueMicrotask(() => {
|
|
20200
|
+
if (!live || firstSent.current === firstMessage.id) return;
|
|
20201
|
+
firstSent.current = firstMessage.id;
|
|
20202
|
+
send(firstMessage.text).then(
|
|
20203
|
+
() => first.current.told?.(firstMessage.id, null),
|
|
20204
|
+
(error) => first.current.told?.(firstMessage.id, error instanceof Error ? error.message : String(error))
|
|
20205
|
+
);
|
|
20206
|
+
});
|
|
20207
|
+
return () => {
|
|
20208
|
+
live = false;
|
|
20209
|
+
};
|
|
20210
|
+
}, [firstMessage, sessionId, effectiveDisabled, send]);
|
|
20211
|
+
const mounted = useRef(false);
|
|
20212
|
+
useEffect(() => {
|
|
20213
|
+
mounted.current = true;
|
|
20214
|
+
return () => {
|
|
20215
|
+
mounted.current = false;
|
|
20216
|
+
queueMicrotask(() => {
|
|
20217
|
+
const { message, told } = first.current;
|
|
20218
|
+
if (mounted.current || !message || firstSent.current === message.id) return;
|
|
20219
|
+
firstSent.current = message.id;
|
|
20220
|
+
told?.(message.id, "The page left the new chat before it was made, so nothing was sent.");
|
|
20221
|
+
});
|
|
20222
|
+
};
|
|
20223
|
+
}, []);
|
|
19246
20224
|
const handleOpenFilePreview = useCallback((path) => {
|
|
19247
20225
|
setWorkspacePath(path);
|
|
19248
20226
|
setPreviewPath(path);
|
|
@@ -19282,7 +20260,11 @@ function AgentChat({
|
|
|
19282
20260
|
adapter,
|
|
19283
20261
|
sessionId,
|
|
19284
20262
|
onFileSelect: handleFileSelect,
|
|
19285
|
-
onOpenBilling
|
|
20263
|
+
onOpenBilling,
|
|
20264
|
+
onOpenSession: onSessionChange,
|
|
20265
|
+
projectId,
|
|
20266
|
+
threadRows,
|
|
20267
|
+
readOnly: disabled === true
|
|
19286
20268
|
},
|
|
19287
20269
|
children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(
|
|
19288
20270
|
"section",
|
|
@@ -19364,7 +20346,7 @@ function AgentChat({
|
|
|
19364
20346
|
isLoadingHistory: runtime.isLoadingHistory,
|
|
19365
20347
|
onSend: (content, images, attachments) => runtime.send(content, images, attachments),
|
|
19366
20348
|
onStop: () => runtime.stop(),
|
|
19367
|
-
onRetry: runtime.retry,
|
|
20349
|
+
onRetry: disabled ? void 0 : runtime.retry,
|
|
19368
20350
|
onFileSelect: handleFileSelect,
|
|
19369
20351
|
disabled: effectiveDisabled,
|
|
19370
20352
|
disabledReason,
|
|
@@ -19382,8 +20364,9 @@ function AgentChat({
|
|
|
19382
20364
|
canShowBrowser: browserAvailable,
|
|
19383
20365
|
canShowWorkspace: workspaceAvailable,
|
|
19384
20366
|
paneCards: {
|
|
19385
|
-
browser:
|
|
19386
|
-
|
|
20367
|
+
// A chat the host only reads offers its browser no card: the card is the way to take it over.
|
|
20368
|
+
browser: browserRunning && !disabled ? {
|
|
20369
|
+
subtitle: browserOnComputer ? browserState?.status === "unavailable" ? "No supported browser on its computer" : "On the chat's computer" : browserState?.controlOwner ? `${browserState.controlOwner} has control` : void 0,
|
|
19387
20370
|
thumbnail: browserPreview,
|
|
19388
20371
|
// Show and hide on the same card, like the Files
|
|
19389
20372
|
// accordion header and the composer's Tools item.
|
|
@@ -19419,7 +20402,9 @@ function AgentChat({
|
|
|
19419
20402
|
researchSources: runtime.researchSources,
|
|
19420
20403
|
hideTurnSummary,
|
|
19421
20404
|
agentId,
|
|
19422
|
-
onOpenIntegrations
|
|
20405
|
+
onOpenIntegrations,
|
|
20406
|
+
deviceWait: runtime.state.deviceWait,
|
|
20407
|
+
composerFooter
|
|
19423
20408
|
}
|
|
19424
20409
|
)
|
|
19425
20410
|
}
|
|
@@ -19445,13 +20430,21 @@ function AgentChat({
|
|
|
19445
20430
|
"data-testid": "browser-panel",
|
|
19446
20431
|
"data-mobile-view": activeMobilePane,
|
|
19447
20432
|
className: "min-h-0 h-full w-full overflow-hidden",
|
|
19448
|
-
children: /* @__PURE__ */ jsx(
|
|
20433
|
+
children: browserOnComputer ? /* @__PURE__ */ jsx(
|
|
20434
|
+
ComputerBrowserPane,
|
|
20435
|
+
{
|
|
20436
|
+
available: browserState.status !== "unavailable",
|
|
20437
|
+
readOnly: disabled === true,
|
|
20438
|
+
draw: computerBrowser
|
|
20439
|
+
}
|
|
20440
|
+
) : /* @__PURE__ */ jsx(
|
|
19449
20441
|
BrowserPane,
|
|
19450
20442
|
{
|
|
19451
20443
|
sessionId,
|
|
19452
20444
|
state: browserState,
|
|
19453
20445
|
adapter,
|
|
19454
|
-
onClose: () => setOpenPane(null)
|
|
20446
|
+
onClose: () => setOpenPane(null),
|
|
20447
|
+
readOnly: disabled === true
|
|
19455
20448
|
}
|
|
19456
20449
|
)
|
|
19457
20450
|
}
|
|
@@ -19556,9 +20549,9 @@ var FetchSseEventStream = class {
|
|
|
19556
20549
|
queueMicrotask(() => void this.start());
|
|
19557
20550
|
}
|
|
19558
20551
|
addEventListener(type, listener) {
|
|
19559
|
-
const
|
|
19560
|
-
|
|
19561
|
-
this.listeners.set(type,
|
|
20552
|
+
const listeners2 = this.listeners.get(type) ?? /* @__PURE__ */ new Set();
|
|
20553
|
+
listeners2.add(listener);
|
|
20554
|
+
this.listeners.set(type, listeners2);
|
|
19562
20555
|
}
|
|
19563
20556
|
close() {
|
|
19564
20557
|
this.watchdog.stop();
|
|
@@ -19635,13 +20628,13 @@ var FetchSseEventStream = class {
|
|
|
19635
20628
|
this.dataLines = [];
|
|
19636
20629
|
return;
|
|
19637
20630
|
}
|
|
19638
|
-
const
|
|
20631
|
+
const listeners2 = this.listeners.get(this.eventType);
|
|
19639
20632
|
const event = {
|
|
19640
20633
|
data: this.dataLines.join("\n"),
|
|
19641
20634
|
lastEventId: this.eventId
|
|
19642
20635
|
};
|
|
19643
|
-
if (
|
|
19644
|
-
for (const listener of
|
|
20636
|
+
if (listeners2) {
|
|
20637
|
+
for (const listener of listeners2) {
|
|
19645
20638
|
listener(event);
|
|
19646
20639
|
}
|
|
19647
20640
|
}
|
|
@@ -21038,218 +22031,6 @@ function CardContent({ className, ...props }) {
|
|
|
21038
22031
|
}
|
|
21039
22032
|
);
|
|
21040
22033
|
}
|
|
21041
|
-
|
|
21042
|
-
// src/components/missions/mission-derive.ts
|
|
21043
|
-
var ACTIVE_MISSION_STATUSES = /* @__PURE__ */ new Set(["active", "paused"]);
|
|
21044
|
-
function isTerminalMissionStatus(status) {
|
|
21045
|
-
return !ACTIVE_MISSION_STATUSES.has(status);
|
|
21046
|
-
}
|
|
21047
|
-
function missionTaskBucket(status) {
|
|
21048
|
-
if (status === "done") return "done";
|
|
21049
|
-
if (status === "blocked") return "blocked";
|
|
21050
|
-
if (status === "failed" || status === "cancelled") {
|
|
21051
|
-
return "failed_or_cancelled";
|
|
21052
|
-
}
|
|
21053
|
-
return "in_flight";
|
|
21054
|
-
}
|
|
21055
|
-
function groupMissionTasksByBucket(tasks) {
|
|
21056
|
-
const buckets = {
|
|
21057
|
-
in_flight: [],
|
|
21058
|
-
done: [],
|
|
21059
|
-
blocked: [],
|
|
21060
|
-
failed_or_cancelled: []
|
|
21061
|
-
};
|
|
21062
|
-
for (const t of tasks) {
|
|
21063
|
-
buckets[missionTaskBucket(t.status)].push(t);
|
|
21064
|
-
}
|
|
21065
|
-
return buckets;
|
|
21066
|
-
}
|
|
21067
|
-
function deriveMissionWorkerActivityLabel(worker) {
|
|
21068
|
-
const kind = worker.latestEventKind;
|
|
21069
|
-
if (kind === "tool.call" && worker.latestEventSummary) {
|
|
21070
|
-
return `tool: ${truncate4(worker.latestEventSummary, 80)}`;
|
|
21071
|
-
}
|
|
21072
|
-
if (kind === "llm.response") {
|
|
21073
|
-
return "thinking";
|
|
21074
|
-
}
|
|
21075
|
-
if (kind === "tool.result") {
|
|
21076
|
-
return "received tool result";
|
|
21077
|
-
}
|
|
21078
|
-
if (kind && worker.latestEventSummary) {
|
|
21079
|
-
return `${kind}: ${truncate4(worker.latestEventSummary, 60)}`;
|
|
21080
|
-
}
|
|
21081
|
-
return worker.sessionStatus || "active";
|
|
21082
|
-
}
|
|
21083
|
-
function truncate4(s, max) {
|
|
21084
|
-
if (s.length <= max) return s;
|
|
21085
|
-
return `${s.slice(0, max - 1)}\u2026`;
|
|
21086
|
-
}
|
|
21087
|
-
var MISSION_EVENT_CATEGORIES = [
|
|
21088
|
-
"spawn",
|
|
21089
|
-
"output",
|
|
21090
|
-
"done",
|
|
21091
|
-
"verdict",
|
|
21092
|
-
"system"
|
|
21093
|
-
];
|
|
21094
|
-
function missionEventCategory(type) {
|
|
21095
|
-
switch (type) {
|
|
21096
|
-
case "worker.spawned":
|
|
21097
|
-
return "spawn";
|
|
21098
|
-
case "iteration.summary":
|
|
21099
|
-
return "output";
|
|
21100
|
-
case "worker.complete":
|
|
21101
|
-
return "done";
|
|
21102
|
-
case "mission.evaluation.end":
|
|
21103
|
-
return "verdict";
|
|
21104
|
-
default:
|
|
21105
|
-
return "system";
|
|
21106
|
-
}
|
|
21107
|
-
}
|
|
21108
|
-
function dataString(data, key) {
|
|
21109
|
-
const v = data?.[key];
|
|
21110
|
-
return typeof v === "string" && v.trim().length > 0 ? v.trim() : null;
|
|
21111
|
-
}
|
|
21112
|
-
var CONTROL_MARKUP_RE = /<next_action\b[^>]*(?:\/>|>[\s\S]*?<\/next_action>)/gi;
|
|
21113
|
-
function stripMissionControlMarkup(text) {
|
|
21114
|
-
return text.replace(CONTROL_MARKUP_RE, "").trim();
|
|
21115
|
-
}
|
|
21116
|
-
function missionEventSummary(event) {
|
|
21117
|
-
return stripMissionControlMarkup(rawMissionEventSummary(event));
|
|
21118
|
-
}
|
|
21119
|
-
function rawMissionEventSummary(event) {
|
|
21120
|
-
const d = event.data ?? null;
|
|
21121
|
-
switch (event.type) {
|
|
21122
|
-
case "worker.spawned":
|
|
21123
|
-
return dataString(d, "goal") ?? "Task spawned";
|
|
21124
|
-
case "worker.complete":
|
|
21125
|
-
return dataString(d, "result") ?? "Worker complete";
|
|
21126
|
-
case "iteration.summary":
|
|
21127
|
-
return dataString(d, "summary") ?? "";
|
|
21128
|
-
case "mission.evaluation.end": {
|
|
21129
|
-
const result = dataString(d, "result");
|
|
21130
|
-
const feedback = dataString(d, "feedback") ?? dataString(d, "explanation");
|
|
21131
|
-
if (result && feedback) return `${result} \u2014 ${feedback}`;
|
|
21132
|
-
return result ?? feedback ?? "Evaluation finished";
|
|
21133
|
-
}
|
|
21134
|
-
case "task.blocked":
|
|
21135
|
-
return dataString(d, "reason") ?? "Task blocked";
|
|
21136
|
-
case "task.failed":
|
|
21137
|
-
return "Task failed";
|
|
21138
|
-
default: {
|
|
21139
|
-
const text = dataString(d, "summary") ?? dataString(d, "text") ?? dataString(d, "message") ?? dataString(d, "reason");
|
|
21140
|
-
if (text) return text;
|
|
21141
|
-
if (!d) return "";
|
|
21142
|
-
try {
|
|
21143
|
-
return truncate4(JSON.stringify(d), 160);
|
|
21144
|
-
} catch {
|
|
21145
|
-
return "";
|
|
21146
|
-
}
|
|
21147
|
-
}
|
|
21148
|
-
}
|
|
21149
|
-
}
|
|
21150
|
-
function missionEventTaskId(event, sessions) {
|
|
21151
|
-
return dataString(event.data ?? null, "task_id") ?? sessions[event.sessionId]?.taskId ?? null;
|
|
21152
|
-
}
|
|
21153
|
-
function missionEventActorLabel(event, sessions) {
|
|
21154
|
-
const meta = sessions[event.sessionId];
|
|
21155
|
-
if (!meta) return event.sessionId.slice(0, 8);
|
|
21156
|
-
if (meta.kind === "coordinator") return "orchestrator";
|
|
21157
|
-
return meta.agentDefName ?? "worker";
|
|
21158
|
-
}
|
|
21159
|
-
function missionTaskBlocks(tasks) {
|
|
21160
|
-
const blocks = {};
|
|
21161
|
-
for (const t of tasks) {
|
|
21162
|
-
for (const parent of t.parentIds) {
|
|
21163
|
-
(blocks[parent] ?? (blocks[parent] = [])).push(t.id);
|
|
21164
|
-
}
|
|
21165
|
-
}
|
|
21166
|
-
return blocks;
|
|
21167
|
-
}
|
|
21168
|
-
function missionTaskTitle(goal, max = 80) {
|
|
21169
|
-
const line = goal.split("\n").find((l) => l.trim().length > 0)?.trim() ?? goal.trim();
|
|
21170
|
-
return truncate4(line.replace(/\s+/g, " "), max);
|
|
21171
|
-
}
|
|
21172
|
-
var RAIL_GROUP_DEFS = [
|
|
21173
|
-
{ key: "running", label: "Running", match: (s) => s === "running" },
|
|
21174
|
-
{ key: "blocked", label: "Blocked", match: (s) => s === "blocked" },
|
|
21175
|
-
{
|
|
21176
|
-
key: "queued",
|
|
21177
|
-
label: "Queued",
|
|
21178
|
-
match: (s) => s === "ready" || s === "todo"
|
|
21179
|
-
},
|
|
21180
|
-
{ key: "done", label: "Done", match: (s) => s === "done" },
|
|
21181
|
-
{
|
|
21182
|
-
key: "failed",
|
|
21183
|
-
label: "Failed / cancelled",
|
|
21184
|
-
match: (s) => s === "failed" || s === "cancelled"
|
|
21185
|
-
}
|
|
21186
|
-
];
|
|
21187
|
-
function missionTaskRailGroups(tasks) {
|
|
21188
|
-
const grouped = /* @__PURE__ */ new Set();
|
|
21189
|
-
const groups = RAIL_GROUP_DEFS.map((def) => ({
|
|
21190
|
-
key: def.key,
|
|
21191
|
-
label: def.label,
|
|
21192
|
-
tasks: tasks.filter((t) => {
|
|
21193
|
-
const hit = def.match(t.status);
|
|
21194
|
-
if (hit) grouped.add(t.id);
|
|
21195
|
-
return hit;
|
|
21196
|
-
})
|
|
21197
|
-
}));
|
|
21198
|
-
const stray = tasks.filter((t) => !grouped.has(t.id));
|
|
21199
|
-
if (stray.length > 0) {
|
|
21200
|
-
const queued = groups.find((g) => g.key === "queued");
|
|
21201
|
-
if (queued) queued.tasks.push(...stray);
|
|
21202
|
-
}
|
|
21203
|
-
return groups.filter((g) => g.tasks.length > 0);
|
|
21204
|
-
}
|
|
21205
|
-
var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
|
|
21206
|
-
function defaultSelectedMissionTaskId(tasks) {
|
|
21207
|
-
if (tasks.length === 0) return null;
|
|
21208
|
-
const ordered = missionTaskRailGroups(tasks).flatMap((g) => g.tasks);
|
|
21209
|
-
const firstLive = ordered.find(
|
|
21210
|
-
(t) => !TERMINAL_TASK_STATUSES.has(t.status)
|
|
21211
|
-
);
|
|
21212
|
-
return (firstLive ?? ordered[0] ?? tasks[0]).id;
|
|
21213
|
-
}
|
|
21214
|
-
function mergeMissionEvents(existing, incoming) {
|
|
21215
|
-
if (incoming.length === 0) return existing;
|
|
21216
|
-
const byId = /* @__PURE__ */ new Map();
|
|
21217
|
-
for (const e of existing) byId.set(e.id, e);
|
|
21218
|
-
for (const e of incoming) byId.set(e.id, e);
|
|
21219
|
-
return [...byId.values()].sort((a, b) => a.id - b.id);
|
|
21220
|
-
}
|
|
21221
|
-
function missionTaskStatusDotClass(status) {
|
|
21222
|
-
switch (status) {
|
|
21223
|
-
case "running":
|
|
21224
|
-
return "bg-primary";
|
|
21225
|
-
case "blocked":
|
|
21226
|
-
return "bg-amber-500";
|
|
21227
|
-
case "done":
|
|
21228
|
-
return "bg-emerald-500";
|
|
21229
|
-
case "failed":
|
|
21230
|
-
return "bg-destructive";
|
|
21231
|
-
case "cancelled":
|
|
21232
|
-
return "bg-muted-foreground";
|
|
21233
|
-
default:
|
|
21234
|
-
return "bg-foreground/30";
|
|
21235
|
-
}
|
|
21236
|
-
}
|
|
21237
|
-
function missionWorkerTaskCounts(worker, tasks) {
|
|
21238
|
-
if (worker.kind !== "task") return null;
|
|
21239
|
-
const mine = tasks.filter((t) => t.agentDefName === worker.agentDefName);
|
|
21240
|
-
return {
|
|
21241
|
-
completed: mine.filter((t) => t.status === "done").length,
|
|
21242
|
-
inFlight: mine.filter(
|
|
21243
|
-
(t) => t.status === "running" || t.status === "blocked"
|
|
21244
|
-
).length
|
|
21245
|
-
};
|
|
21246
|
-
}
|
|
21247
|
-
function formatMissionTimestamp(iso) {
|
|
21248
|
-
if (!iso) return "";
|
|
21249
|
-
const parsed = new Date(iso);
|
|
21250
|
-
if (Number.isNaN(parsed.getTime())) return iso;
|
|
21251
|
-
return parsed.toLocaleTimeString();
|
|
21252
|
-
}
|
|
21253
22034
|
var CATEGORY_BADGE_CLASS = {
|
|
21254
22035
|
spawn: "border-primary/30 bg-primary/10 text-primary",
|
|
21255
22036
|
output: "border-foreground/20 bg-foreground/5 text-foreground/80",
|
|
@@ -21902,7 +22683,7 @@ function MissionWorkersTab({
|
|
|
21902
22683
|
return /* @__PURE__ */ jsx("div", { className: "py-8 text-center text-sm text-muted-foreground/60", children: "No workers attached to this mission right now." });
|
|
21903
22684
|
}
|
|
21904
22685
|
return /* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2", children: workers.map((w) => /* @__PURE__ */ jsx(
|
|
21905
|
-
|
|
22686
|
+
WorkerCard2,
|
|
21906
22687
|
{
|
|
21907
22688
|
worker: w,
|
|
21908
22689
|
tasks,
|
|
@@ -21911,7 +22692,7 @@ function MissionWorkersTab({
|
|
|
21911
22692
|
w.workerSessionId
|
|
21912
22693
|
)) });
|
|
21913
22694
|
}
|
|
21914
|
-
function
|
|
22695
|
+
function WorkerCard2({
|
|
21915
22696
|
worker,
|
|
21916
22697
|
tasks,
|
|
21917
22698
|
onOpenTranscript
|
|
@@ -23096,6 +23877,7 @@ function sessionToTreeNode(session) {
|
|
|
23096
23877
|
model: session.model,
|
|
23097
23878
|
messageCount: session.messageCount,
|
|
23098
23879
|
toolCallCount: session.toolCallCount,
|
|
23880
|
+
computer: sessionComputer(session.config),
|
|
23099
23881
|
createdAt: session.createdAt ?? timestamp,
|
|
23100
23882
|
updatedAt: session.updatedAt ?? timestamp
|
|
23101
23883
|
};
|
|
@@ -23122,13 +23904,13 @@ function mergeTreeNodes(groups) {
|
|
|
23122
23904
|
}
|
|
23123
23905
|
function collectDeletedSessionIds(nodes, deletedSessionId) {
|
|
23124
23906
|
const deletedIds = /* @__PURE__ */ new Set([deletedSessionId]);
|
|
23125
|
-
let
|
|
23126
|
-
while (
|
|
23127
|
-
|
|
23907
|
+
let changed2 = true;
|
|
23908
|
+
while (changed2) {
|
|
23909
|
+
changed2 = false;
|
|
23128
23910
|
for (const node of nodes) {
|
|
23129
23911
|
if (node.parentId && deletedIds.has(node.parentId) && !deletedIds.has(node.id)) {
|
|
23130
23912
|
deletedIds.add(node.id);
|
|
23131
|
-
|
|
23913
|
+
changed2 = true;
|
|
23132
23914
|
}
|
|
23133
23915
|
}
|
|
23134
23916
|
}
|
|
@@ -23224,7 +24006,15 @@ function TreeNodeRow({
|
|
|
23224
24006
|
) : /* @__PURE__ */ jsx("span", { className: "w-4 h-4 shrink-0" }),
|
|
23225
24007
|
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
23226
24008
|
/* @__PURE__ */ jsx("div", { className: "text-sm truncate", children: title }),
|
|
23227
|
-
/* @__PURE__ */
|
|
24009
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-faint min-w-0", children: [
|
|
24010
|
+
entry.computer && // A chat on a folder of the user's computer, in every list of chats, the browser's too.
|
|
24011
|
+
/* @__PURE__ */ jsxs("span", { "data-testid": "session-computer", title: `On ${entry.computer}`, className: "inline-flex min-w-0 max-w-[50%] items-center gap-1", children: [
|
|
24012
|
+
/* @__PURE__ */ jsx(LaptopIcon, { className: "w-3 h-3 shrink-0", "aria-hidden": "true" }),
|
|
24013
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: entry.computer })
|
|
24014
|
+
] }),
|
|
24015
|
+
entry.computer && subtitle && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }),
|
|
24016
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: subtitle })
|
|
24017
|
+
] })
|
|
23228
24018
|
] }),
|
|
23229
24019
|
isRunning && canStop && isChildSession && /* @__PURE__ */ jsx(
|
|
23230
24020
|
"button",
|
|
@@ -23321,9 +24111,10 @@ function SessionTreePanel({
|
|
|
23321
24111
|
}
|
|
23322
24112
|
const sessionList = listResult.status === "fulfilled" ? listResult.value : null;
|
|
23323
24113
|
const sessionTree = treeResult.status === "fulfilled" ? treeResult.value : null;
|
|
24114
|
+
const project = sessionTree?.nodes.some((node) => node.parentId === null && node.runKind === "project");
|
|
23324
24115
|
let nextNodes = mergeTreeNodes([
|
|
23325
24116
|
sessionList?.sessions.map(sessionToTreeNode) ?? [],
|
|
23326
|
-
sessionTree?.nodes ?? []
|
|
24117
|
+
project ? [] : sessionTree?.nodes ?? []
|
|
23327
24118
|
]);
|
|
23328
24119
|
if (pendingDeleteIds.current.size > 0) {
|
|
23329
24120
|
const stillReturned = /* @__PURE__ */ new Set();
|
|
@@ -23475,6 +24266,6 @@ function SessionTreePanel({
|
|
|
23475
24266
|
] });
|
|
23476
24267
|
}
|
|
23477
24268
|
|
|
23478
|
-
export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, AgentWhiteboard, BrandBeam, BrowserShell, CitationText, CodingAgentsPanel, ComposioConnectCard, FetchSseEventStream, InboxPanel, IntegrationsBand, IntegrationsPage, MISSION_EVENT_CATEGORIES, MessageResponse, MissionDashboard, MissionsPanel, ORB_STATE_LABELS, OrbShimmerLabel, ResearchSourcesPanel, SIMPLE_MODE_HIDDEN_TOOLS, SIMPLE_MODE_ORB_OPTIONS, ScheduledWorkPanel, SessionTreePanel, WhiteboardSurface, defaultSelectedMissionTaskId, deriveMissionWorkerActivityLabel, deriveOrbActivity, formatMissionTimestamp, groupMissionTasksByBucket, isHiddenSimpleTool, isTerminalMissionStatus, mergeMissionEvents, messageOrbState, missionEventActorLabel, missionEventCategory, missionEventSummary, missionEventTaskId, missionTaskBlocks, missionTaskBucket, missionTaskRailGroups, missionTaskStatusDotClass, missionTaskTitle, missionWorkerTaskCounts, persistChatViewMode, splitCitations, stripMissionControlMarkup, toolOrbState, useAgentChatAdapterContext, useAgentChatRuntime, useBrowserControl, useChatViewMode, useInboxUnreadCount, useMissionEvents };
|
|
24269
|
+
export { ACTIVE_MISSION_STATUSES, AgentChat, AgentChatAdapterProvider, AgentWhiteboard, BrandBeam, BrowserShell, CitationText, CodingAgentsPanel, ComposioConnectCard, FetchSseEventStream, InboxPanel, IntegrationsBand, IntegrationsPage, MISSION_EVENT_CATEGORIES, MessageResponse, MissionDashboard, MissionsPanel, ORB_STATE_LABELS, OrbShimmerLabel, ResearchSourcesPanel, SIMPLE_MODE_HIDDEN_TOOLS, SIMPLE_MODE_ORB_OPTIONS, ScheduledWorkPanel, SessionTreePanel, WhiteboardSurface, defaultSelectedMissionTaskId, deriveMissionWorkerActivityLabel, deriveOrbActivity, forgetChatFiles, formatMissionTimestamp, groupMissionTasksByBucket, isHiddenSimpleTool, isTerminalMissionStatus, mergeMissionEvents, messageOrbState, missionEventActorLabel, missionEventCategory, missionEventSummary, missionEventTaskId, missionTaskBlocks, missionTaskBucket, missionTaskRailGroups, missionTaskStatusDotClass, missionTaskTitle, missionWorkerTaskCounts, persistChatViewMode, sessionComputer, splitCitations, stripMissionControlMarkup, toolOrbState, useAgentChatAdapterContext, useAgentChatRuntime, useBrowserControl, useChatViewMode, useInboxUnreadCount, useMissionEvents };
|
|
23479
24270
|
//# sourceMappingURL=index.js.map
|
|
23480
24271
|
//# sourceMappingURL=index.js.map
|