@invergent/agent-chat-react 1.5.10 → 1.6.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 +595 -238
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -2
- package/dist/index.d.ts +21 -2
- package/dist/index.js +568 -212
- 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 } from './chunk-QSC4UIVT.js';
|
|
2
2
|
import { createContext, memo, useRef, useState, useEffect, useCallback, useMemo, lazy, useContext, Suspense, Children } from 'react';
|
|
3
|
+
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, GlobeIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CheckIcon, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, ZapIcon, Maximize2Icon, PlayIcon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
3
4
|
import { cva } from 'class-variance-authority';
|
|
4
5
|
import { Collapsible as Collapsible$1, Slot, Dialog as Dialog$1, ScrollArea as ScrollArea$1, Tooltip as Tooltip$1, Tabs as Tabs$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, HoverCard as HoverCard$1, Progress as Progress$1 } from 'radix-ui';
|
|
5
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
import { ChevronDownIcon, AlertTriangle, ChevronDown, ChevronRight, RefreshCw, ChevronRightIcon, GitBranchIcon, XIcon, ThumbsUpIcon, ThumbsDownIcon, ActivityIcon, Loader2Icon, GlobeIcon, SearchIcon, ListTodoIcon, XCircleIcon, CheckCircle2Icon, Code, CheckIcon, CopyIcon, TerminalIcon, Trash2Icon, CircleDotIcon, CircleCheckIcon, CircleXIcon, SkullIcon, ClockIcon, CheckCircleIcon, CircleIcon, CalendarClockIcon, UsersIcon, MessageSquareIcon, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, SquareIcon, ArrowDownIcon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, Maximize2Icon, FolderIcon, FileIcon, ChevronLeftIcon, MinusIcon, PlusIcon, CornerDownLeftIcon } from 'lucide-react';
|
|
7
7
|
import { StickToBottom, useStickToBottomContext } from 'use-stick-to-bottom';
|
|
8
8
|
import { cjk } from '@streamdown/cjk';
|
|
9
9
|
import { code } from '@streamdown/code';
|
|
@@ -79,6 +79,353 @@ function Button({
|
|
|
79
79
|
}
|
|
80
80
|
);
|
|
81
81
|
}
|
|
82
|
+
function BrowserControlBar({
|
|
83
|
+
sessionId,
|
|
84
|
+
hasControl,
|
|
85
|
+
adapter
|
|
86
|
+
}) {
|
|
87
|
+
const [pending, setPending] = useState(false);
|
|
88
|
+
const [error, setError] = useState(null);
|
|
89
|
+
async function toggleControl() {
|
|
90
|
+
if (!sessionId || pending) return;
|
|
91
|
+
setPending(true);
|
|
92
|
+
setError(null);
|
|
93
|
+
try {
|
|
94
|
+
if (hasControl) {
|
|
95
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
96
|
+
} else {
|
|
97
|
+
await adapter.acquireBrowserControl(sessionId);
|
|
98
|
+
}
|
|
99
|
+
} catch (nextError) {
|
|
100
|
+
setError(nextError.message);
|
|
101
|
+
} finally {
|
|
102
|
+
setPending(false);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
106
|
+
/* @__PURE__ */ jsxs(
|
|
107
|
+
Button,
|
|
108
|
+
{
|
|
109
|
+
type: "button",
|
|
110
|
+
size: "xs",
|
|
111
|
+
variant: hasControl ? "secondary" : "default",
|
|
112
|
+
disabled: !sessionId || pending,
|
|
113
|
+
onClick: () => void toggleControl(),
|
|
114
|
+
children: [
|
|
115
|
+
hasControl ? /* @__PURE__ */ jsx(RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
116
|
+
hasControl ? "Return control" : "Take control"
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
122
|
+
"Live"
|
|
123
|
+
] }),
|
|
124
|
+
error && /* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error })
|
|
125
|
+
] });
|
|
126
|
+
}
|
|
127
|
+
function BrowserLiveView({
|
|
128
|
+
src,
|
|
129
|
+
testId = "browser-iframe"
|
|
130
|
+
}) {
|
|
131
|
+
return /* @__PURE__ */ jsx(
|
|
132
|
+
"iframe",
|
|
133
|
+
{
|
|
134
|
+
"data-testid": testId,
|
|
135
|
+
title: "Browser live view",
|
|
136
|
+
src,
|
|
137
|
+
className: "h-full w-full border-0 bg-black",
|
|
138
|
+
allow: "clipboard-read; clipboard-write"
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
function BrowserStatusDot({
|
|
143
|
+
status
|
|
144
|
+
}) {
|
|
145
|
+
return /* @__PURE__ */ jsx(
|
|
146
|
+
"span",
|
|
147
|
+
{
|
|
148
|
+
"aria-hidden": "true",
|
|
149
|
+
className: cn(
|
|
150
|
+
"inline-block size-2 shrink-0 rounded-full",
|
|
151
|
+
status === "live" && "bg-emerald-500",
|
|
152
|
+
status === "user-control" && "bg-amber-500",
|
|
153
|
+
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
154
|
+
status === "closed" && "bg-muted-foreground"
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
function Dialog({
|
|
160
|
+
...props
|
|
161
|
+
}) {
|
|
162
|
+
return /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
|
|
163
|
+
}
|
|
164
|
+
function DialogPortal({
|
|
165
|
+
...props
|
|
166
|
+
}) {
|
|
167
|
+
return /* @__PURE__ */ jsx(Dialog$1.Portal, { "data-slot": "dialog-portal", ...props });
|
|
168
|
+
}
|
|
169
|
+
function DialogOverlay({
|
|
170
|
+
className,
|
|
171
|
+
...props
|
|
172
|
+
}) {
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
Dialog$1.Overlay,
|
|
175
|
+
{
|
|
176
|
+
"data-slot": "dialog-overlay",
|
|
177
|
+
className: cn(
|
|
178
|
+
"fixed inset-0 isolate z-50 bg-black/20 duration-100 supports-backdrop-filter:backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
179
|
+
className
|
|
180
|
+
),
|
|
181
|
+
...props
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
function DialogContent({
|
|
186
|
+
className,
|
|
187
|
+
children,
|
|
188
|
+
showCloseButton = true,
|
|
189
|
+
...props
|
|
190
|
+
}) {
|
|
191
|
+
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
192
|
+
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
193
|
+
/* @__PURE__ */ jsxs(
|
|
194
|
+
Dialog$1.Content,
|
|
195
|
+
{
|
|
196
|
+
"data-slot": "dialog-content",
|
|
197
|
+
className: cn(
|
|
198
|
+
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-none bg-popover p-6 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-md 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",
|
|
199
|
+
className
|
|
200
|
+
),
|
|
201
|
+
...props,
|
|
202
|
+
children: [
|
|
203
|
+
children,
|
|
204
|
+
showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs(
|
|
205
|
+
Button,
|
|
206
|
+
{
|
|
207
|
+
variant: "ghost",
|
|
208
|
+
className: "absolute top-5 right-5 bg-secondary",
|
|
209
|
+
size: "icon-sm",
|
|
210
|
+
children: [
|
|
211
|
+
/* @__PURE__ */ jsx(
|
|
212
|
+
XIcon,
|
|
213
|
+
{}
|
|
214
|
+
),
|
|
215
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
) })
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
] });
|
|
223
|
+
}
|
|
224
|
+
function DialogHeader({ className, ...props }) {
|
|
225
|
+
return /* @__PURE__ */ jsx(
|
|
226
|
+
"div",
|
|
227
|
+
{
|
|
228
|
+
"data-slot": "dialog-header",
|
|
229
|
+
className: cn("flex flex-col gap-2", className),
|
|
230
|
+
...props
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
function DialogFooter({
|
|
235
|
+
className,
|
|
236
|
+
showCloseButton = false,
|
|
237
|
+
children,
|
|
238
|
+
...props
|
|
239
|
+
}) {
|
|
240
|
+
return /* @__PURE__ */ jsxs(
|
|
241
|
+
"div",
|
|
242
|
+
{
|
|
243
|
+
"data-slot": "dialog-footer",
|
|
244
|
+
className: cn(
|
|
245
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
246
|
+
className
|
|
247
|
+
),
|
|
248
|
+
...props,
|
|
249
|
+
children: [
|
|
250
|
+
children,
|
|
251
|
+
showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", children: "Close" }) })
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
function DialogTitle({
|
|
257
|
+
className,
|
|
258
|
+
...props
|
|
259
|
+
}) {
|
|
260
|
+
return /* @__PURE__ */ jsx(
|
|
261
|
+
Dialog$1.Title,
|
|
262
|
+
{
|
|
263
|
+
"data-slot": "dialog-title",
|
|
264
|
+
className: cn(
|
|
265
|
+
"font-heading text-lg leading-none font-semibold tracking-wider uppercase",
|
|
266
|
+
className
|
|
267
|
+
),
|
|
268
|
+
...props
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
function DialogDescription({
|
|
273
|
+
className,
|
|
274
|
+
...props
|
|
275
|
+
}) {
|
|
276
|
+
return /* @__PURE__ */ jsx(
|
|
277
|
+
Dialog$1.Description,
|
|
278
|
+
{
|
|
279
|
+
"data-slot": "dialog-description",
|
|
280
|
+
className: cn(
|
|
281
|
+
"mt-0.5 text-sm leading-relaxed text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
282
|
+
className
|
|
283
|
+
),
|
|
284
|
+
...props
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
function TooltipProvider({
|
|
289
|
+
delayDuration = 0,
|
|
290
|
+
...props
|
|
291
|
+
}) {
|
|
292
|
+
return /* @__PURE__ */ jsx(
|
|
293
|
+
Tooltip$1.Provider,
|
|
294
|
+
{
|
|
295
|
+
"data-slot": "tooltip-provider",
|
|
296
|
+
delayDuration,
|
|
297
|
+
...props
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function Tooltip({
|
|
302
|
+
...props
|
|
303
|
+
}) {
|
|
304
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
|
|
305
|
+
}
|
|
306
|
+
function TooltipTrigger({
|
|
307
|
+
...props
|
|
308
|
+
}) {
|
|
309
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
310
|
+
}
|
|
311
|
+
function TooltipContent({
|
|
312
|
+
className,
|
|
313
|
+
sideOffset = 0,
|
|
314
|
+
children,
|
|
315
|
+
...props
|
|
316
|
+
}) {
|
|
317
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsxs(
|
|
318
|
+
Tooltip$1.Content,
|
|
319
|
+
{
|
|
320
|
+
"data-slot": "tooltip-content",
|
|
321
|
+
sideOffset,
|
|
322
|
+
className: cn(
|
|
323
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-none bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 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-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 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",
|
|
324
|
+
className
|
|
325
|
+
),
|
|
326
|
+
...props,
|
|
327
|
+
children: [
|
|
328
|
+
children,
|
|
329
|
+
/* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-none bg-foreground fill-foreground" })
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
) });
|
|
333
|
+
}
|
|
334
|
+
function BrowserPane({ sessionId, state, adapter }) {
|
|
335
|
+
const [fullscreenOpen, setFullscreenOpen] = useState(false);
|
|
336
|
+
const [inlinePreviewOpen, setInlinePreviewOpen] = useState(false);
|
|
337
|
+
const hasLiveViewAdapter = typeof adapter.browserLiveViewUrl === "function";
|
|
338
|
+
const hasControlAdapter = typeof adapter.acquireBrowserControl === "function" && typeof adapter.releaseBrowserControl === "function";
|
|
339
|
+
const liveViewUrl = useMemo(() => {
|
|
340
|
+
if (!hasLiveViewAdapter) return "";
|
|
341
|
+
return adapter.browserLiveViewUrl(sessionId);
|
|
342
|
+
}, [adapter, hasLiveViewAdapter, sessionId]);
|
|
343
|
+
const hasLiveView = state.status !== "provisioning" && state.status !== "closed";
|
|
344
|
+
const canOpenFullscreen = hasLiveView && Boolean(liveViewUrl);
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
setFullscreenOpen(false);
|
|
347
|
+
setInlinePreviewOpen(false);
|
|
348
|
+
}, [sessionId]);
|
|
349
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
350
|
+
/* @__PURE__ */ jsxs(
|
|
351
|
+
"div",
|
|
352
|
+
{
|
|
353
|
+
"data-testid": "browser-pane",
|
|
354
|
+
className: "flex h-full min-h-0 flex-col bg-background",
|
|
355
|
+
children: [
|
|
356
|
+
/* @__PURE__ */ jsxs("header", { className: "flex min-h-10 items-center gap-2 border-b border-line bg-card px-3 text-xs text-foreground", children: [
|
|
357
|
+
/* @__PURE__ */ jsx(ZapIcon, { className: "size-3.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
358
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Browser" }),
|
|
359
|
+
/* @__PURE__ */ jsx(BrowserStatusDot, { status: state.status }),
|
|
360
|
+
state.controlOwner && /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-amber-500", children: [
|
|
361
|
+
state.controlOwner,
|
|
362
|
+
" has control"
|
|
363
|
+
] }),
|
|
364
|
+
canOpenFullscreen && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center", children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
365
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
366
|
+
"button",
|
|
367
|
+
{
|
|
368
|
+
type: "button",
|
|
369
|
+
"aria-label": "Maximize browser",
|
|
370
|
+
className: "inline-flex size-7 items-center justify-center text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
371
|
+
onClick: () => setFullscreenOpen(true),
|
|
372
|
+
children: /* @__PURE__ */ jsx(Maximize2Icon, { className: "size-3.5", "aria-hidden": "true" })
|
|
373
|
+
}
|
|
374
|
+
) }),
|
|
375
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "bottom", children: "Full screen" })
|
|
376
|
+
] }) }) })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : liveViewUrl && inlinePreviewOpen ? /* @__PURE__ */ jsx(BrowserLiveView, { src: liveViewUrl }) : liveViewUrl ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: /* @__PURE__ */ jsxs(
|
|
379
|
+
"button",
|
|
380
|
+
{
|
|
381
|
+
type: "button",
|
|
382
|
+
"aria-label": "Open browser live preview",
|
|
383
|
+
className: "inline-flex items-center gap-2 border border-line bg-card px-3 py-2 text-xs font-medium text-foreground transition-colors hover:bg-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
384
|
+
onClick: () => setInlinePreviewOpen(true),
|
|
385
|
+
children: [
|
|
386
|
+
/* @__PURE__ */ jsx(PlayIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
387
|
+
/* @__PURE__ */ jsx("span", { children: "Open live preview" })
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
) }) : /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser live view is unavailable." }) }),
|
|
391
|
+
hasLiveView && hasControlAdapter && /* @__PURE__ */ jsx(
|
|
392
|
+
BrowserControlBar,
|
|
393
|
+
{
|
|
394
|
+
sessionId,
|
|
395
|
+
hasControl: state.status === "user-control",
|
|
396
|
+
adapter
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
),
|
|
402
|
+
/* @__PURE__ */ jsx(Dialog, { open: fullscreenOpen, onOpenChange: setFullscreenOpen, children: /* @__PURE__ */ jsxs(
|
|
403
|
+
DialogContent,
|
|
404
|
+
{
|
|
405
|
+
"aria-describedby": void 0,
|
|
406
|
+
className: "flex h-screen w-screen max-w-none flex-col gap-0 overflow-hidden rounded-none border-0 bg-background p-0 shadow-none ring-0 sm:max-w-none",
|
|
407
|
+
children: [
|
|
408
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "h-10 shrink-0 flex-row items-center gap-2 border-b border-line bg-card px-4 py-0", children: [
|
|
409
|
+
/* @__PURE__ */ jsx(ZapIcon, { className: "size-3.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
410
|
+
/* @__PURE__ */ jsx(DialogTitle, { className: "text-xs normal-case tracking-normal", children: "Browser" }),
|
|
411
|
+
/* @__PURE__ */ jsx(BrowserStatusDot, { status: state.status }),
|
|
412
|
+
state.controlOwner && /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-xs text-amber-500", children: [
|
|
413
|
+
state.controlOwner,
|
|
414
|
+
" has control"
|
|
415
|
+
] })
|
|
416
|
+
] }),
|
|
417
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 bg-black", children: liveViewUrl ? /* @__PURE__ */ jsx(
|
|
418
|
+
BrowserLiveView,
|
|
419
|
+
{
|
|
420
|
+
src: liveViewUrl,
|
|
421
|
+
testId: "browser-fullscreen-iframe"
|
|
422
|
+
}
|
|
423
|
+
) : /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser live view is unavailable." }) })
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
) })
|
|
427
|
+
] });
|
|
428
|
+
}
|
|
82
429
|
var Conversation = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
83
430
|
StickToBottom,
|
|
84
431
|
{
|
|
@@ -147,52 +494,6 @@ var ConversationScrollButton = ({
|
|
|
147
494
|
}
|
|
148
495
|
);
|
|
149
496
|
};
|
|
150
|
-
function TooltipProvider({
|
|
151
|
-
delayDuration = 0,
|
|
152
|
-
...props
|
|
153
|
-
}) {
|
|
154
|
-
return /* @__PURE__ */ jsx(
|
|
155
|
-
Tooltip$1.Provider,
|
|
156
|
-
{
|
|
157
|
-
"data-slot": "tooltip-provider",
|
|
158
|
-
delayDuration,
|
|
159
|
-
...props
|
|
160
|
-
}
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
function Tooltip({
|
|
164
|
-
...props
|
|
165
|
-
}) {
|
|
166
|
-
return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
|
|
167
|
-
}
|
|
168
|
-
function TooltipTrigger({
|
|
169
|
-
...props
|
|
170
|
-
}) {
|
|
171
|
-
return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
172
|
-
}
|
|
173
|
-
function TooltipContent({
|
|
174
|
-
className,
|
|
175
|
-
sideOffset = 0,
|
|
176
|
-
children,
|
|
177
|
-
...props
|
|
178
|
-
}) {
|
|
179
|
-
return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsxs(
|
|
180
|
-
Tooltip$1.Content,
|
|
181
|
-
{
|
|
182
|
-
"data-slot": "tooltip-content",
|
|
183
|
-
sideOffset,
|
|
184
|
-
className: cn(
|
|
185
|
-
"z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-none bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 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-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-none data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 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",
|
|
186
|
-
className
|
|
187
|
-
),
|
|
188
|
-
...props,
|
|
189
|
-
children: [
|
|
190
|
-
children,
|
|
191
|
-
/* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-none bg-foreground fill-foreground" })
|
|
192
|
-
]
|
|
193
|
-
}
|
|
194
|
-
) });
|
|
195
|
-
}
|
|
196
497
|
var Message = ({ className, from, ...props }) => /* @__PURE__ */ jsx(
|
|
197
498
|
"div",
|
|
198
499
|
{
|
|
@@ -565,6 +866,80 @@ function TimelineSeparator({
|
|
|
565
866
|
}
|
|
566
867
|
);
|
|
567
868
|
}
|
|
869
|
+
function BrowserActivityGroup({ calls }) {
|
|
870
|
+
const [open, setOpen] = useState(false);
|
|
871
|
+
const latest = calls[calls.length - 1];
|
|
872
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-none border border-line bg-card text-xs", children: [
|
|
873
|
+
/* @__PURE__ */ jsxs(
|
|
874
|
+
"button",
|
|
875
|
+
{
|
|
876
|
+
type: "button",
|
|
877
|
+
onClick: () => setOpen((current) => !current),
|
|
878
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted/40",
|
|
879
|
+
children: [
|
|
880
|
+
open ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }),
|
|
881
|
+
/* @__PURE__ */ jsx(ZapIcon, { className: "size-3 shrink-0 text-amber-500", "aria-hidden": "true" }),
|
|
882
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "browser" }),
|
|
883
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-muted-foreground", children: [
|
|
884
|
+
"(",
|
|
885
|
+
calls.length,
|
|
886
|
+
" ",
|
|
887
|
+
calls.length === 1 ? "action" : "actions",
|
|
888
|
+
" - latest:",
|
|
889
|
+
" ",
|
|
890
|
+
latest ? summarise(latest) : "none",
|
|
891
|
+
")"
|
|
892
|
+
] })
|
|
893
|
+
]
|
|
894
|
+
}
|
|
895
|
+
),
|
|
896
|
+
open && /* @__PURE__ */ jsx("ul", { className: "border-t border-line py-1", children: calls.map((call) => {
|
|
897
|
+
const error = stringValue(parseJson(call.result).error);
|
|
898
|
+
return /* @__PURE__ */ jsxs(
|
|
899
|
+
"li",
|
|
900
|
+
{
|
|
901
|
+
className: "flex items-center gap-2 px-6 py-1 font-mono text-[11px]",
|
|
902
|
+
children: [
|
|
903
|
+
error && /* @__PURE__ */ jsx(
|
|
904
|
+
AlertCircleIcon,
|
|
905
|
+
{
|
|
906
|
+
"data-testid": `activity-error-${call.id}`,
|
|
907
|
+
className: "size-3 shrink-0 text-destructive",
|
|
908
|
+
"aria-hidden": "true"
|
|
909
|
+
}
|
|
910
|
+
),
|
|
911
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: summarise(call) }),
|
|
912
|
+
error && /* @__PURE__ */ jsx("span", { className: "ml-auto max-w-40 truncate text-destructive", children: error })
|
|
913
|
+
]
|
|
914
|
+
},
|
|
915
|
+
call.id
|
|
916
|
+
);
|
|
917
|
+
}) })
|
|
918
|
+
] });
|
|
919
|
+
}
|
|
920
|
+
function summarise(call) {
|
|
921
|
+
const verb = call.toolName.replace(/^browser_/, "");
|
|
922
|
+
const args = parseJson(call.args);
|
|
923
|
+
const ref = stringValue(args.ref);
|
|
924
|
+
const url = stringValue(args.url);
|
|
925
|
+
const text = stringValue(args.text);
|
|
926
|
+
if (url) return `${verb} ${url}`;
|
|
927
|
+
if (ref) return `${verb} ${ref}`;
|
|
928
|
+
if (text) return `${verb} "${text.slice(0, 24)}"`;
|
|
929
|
+
return verb;
|
|
930
|
+
}
|
|
931
|
+
function parseJson(raw) {
|
|
932
|
+
if (!raw) return {};
|
|
933
|
+
try {
|
|
934
|
+
const parsed = JSON.parse(raw);
|
|
935
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
936
|
+
} catch {
|
|
937
|
+
return {};
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
function stringValue(value) {
|
|
941
|
+
return typeof value === "string" ? value : "";
|
|
942
|
+
}
|
|
568
943
|
|
|
569
944
|
// src/components/chat/tools/shared.ts
|
|
570
945
|
function statusColorClass(status) {
|
|
@@ -1591,135 +1966,6 @@ function WebToolBlock({ tc }) {
|
|
|
1591
1966
|
displayText && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 truncate text-xs", children: displayText })
|
|
1592
1967
|
] });
|
|
1593
1968
|
}
|
|
1594
|
-
function Dialog({
|
|
1595
|
-
...props
|
|
1596
|
-
}) {
|
|
1597
|
-
return /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
|
|
1598
|
-
}
|
|
1599
|
-
function DialogPortal({
|
|
1600
|
-
...props
|
|
1601
|
-
}) {
|
|
1602
|
-
return /* @__PURE__ */ jsx(Dialog$1.Portal, { "data-slot": "dialog-portal", ...props });
|
|
1603
|
-
}
|
|
1604
|
-
function DialogOverlay({
|
|
1605
|
-
className,
|
|
1606
|
-
...props
|
|
1607
|
-
}) {
|
|
1608
|
-
return /* @__PURE__ */ jsx(
|
|
1609
|
-
Dialog$1.Overlay,
|
|
1610
|
-
{
|
|
1611
|
-
"data-slot": "dialog-overlay",
|
|
1612
|
-
className: cn(
|
|
1613
|
-
"fixed inset-0 isolate z-50 bg-black/20 duration-100 supports-backdrop-filter:backdrop-blur-sm data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
1614
|
-
className
|
|
1615
|
-
),
|
|
1616
|
-
...props
|
|
1617
|
-
}
|
|
1618
|
-
);
|
|
1619
|
-
}
|
|
1620
|
-
function DialogContent({
|
|
1621
|
-
className,
|
|
1622
|
-
children,
|
|
1623
|
-
showCloseButton = true,
|
|
1624
|
-
...props
|
|
1625
|
-
}) {
|
|
1626
|
-
return /* @__PURE__ */ jsxs(DialogPortal, { children: [
|
|
1627
|
-
/* @__PURE__ */ jsx(DialogOverlay, {}),
|
|
1628
|
-
/* @__PURE__ */ jsxs(
|
|
1629
|
-
Dialog$1.Content,
|
|
1630
|
-
{
|
|
1631
|
-
"data-slot": "dialog-content",
|
|
1632
|
-
className: cn(
|
|
1633
|
-
"fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-none bg-popover p-6 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-md 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",
|
|
1634
|
-
className
|
|
1635
|
-
),
|
|
1636
|
-
...props,
|
|
1637
|
-
children: [
|
|
1638
|
-
children,
|
|
1639
|
-
showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxs(
|
|
1640
|
-
Button,
|
|
1641
|
-
{
|
|
1642
|
-
variant: "ghost",
|
|
1643
|
-
className: "absolute top-5 right-5 bg-secondary",
|
|
1644
|
-
size: "icon-sm",
|
|
1645
|
-
children: [
|
|
1646
|
-
/* @__PURE__ */ jsx(
|
|
1647
|
-
XIcon,
|
|
1648
|
-
{}
|
|
1649
|
-
),
|
|
1650
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
|
|
1651
|
-
]
|
|
1652
|
-
}
|
|
1653
|
-
) })
|
|
1654
|
-
]
|
|
1655
|
-
}
|
|
1656
|
-
)
|
|
1657
|
-
] });
|
|
1658
|
-
}
|
|
1659
|
-
function DialogHeader({ className, ...props }) {
|
|
1660
|
-
return /* @__PURE__ */ jsx(
|
|
1661
|
-
"div",
|
|
1662
|
-
{
|
|
1663
|
-
"data-slot": "dialog-header",
|
|
1664
|
-
className: cn("flex flex-col gap-2", className),
|
|
1665
|
-
...props
|
|
1666
|
-
}
|
|
1667
|
-
);
|
|
1668
|
-
}
|
|
1669
|
-
function DialogFooter({
|
|
1670
|
-
className,
|
|
1671
|
-
showCloseButton = false,
|
|
1672
|
-
children,
|
|
1673
|
-
...props
|
|
1674
|
-
}) {
|
|
1675
|
-
return /* @__PURE__ */ jsxs(
|
|
1676
|
-
"div",
|
|
1677
|
-
{
|
|
1678
|
-
"data-slot": "dialog-footer",
|
|
1679
|
-
className: cn(
|
|
1680
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1681
|
-
className
|
|
1682
|
-
),
|
|
1683
|
-
...props,
|
|
1684
|
-
children: [
|
|
1685
|
-
children,
|
|
1686
|
-
showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", children: "Close" }) })
|
|
1687
|
-
]
|
|
1688
|
-
}
|
|
1689
|
-
);
|
|
1690
|
-
}
|
|
1691
|
-
function DialogTitle({
|
|
1692
|
-
className,
|
|
1693
|
-
...props
|
|
1694
|
-
}) {
|
|
1695
|
-
return /* @__PURE__ */ jsx(
|
|
1696
|
-
Dialog$1.Title,
|
|
1697
|
-
{
|
|
1698
|
-
"data-slot": "dialog-title",
|
|
1699
|
-
className: cn(
|
|
1700
|
-
"font-heading text-lg leading-none font-semibold tracking-wider uppercase",
|
|
1701
|
-
className
|
|
1702
|
-
),
|
|
1703
|
-
...props
|
|
1704
|
-
}
|
|
1705
|
-
);
|
|
1706
|
-
}
|
|
1707
|
-
function DialogDescription({
|
|
1708
|
-
className,
|
|
1709
|
-
...props
|
|
1710
|
-
}) {
|
|
1711
|
-
return /* @__PURE__ */ jsx(
|
|
1712
|
-
Dialog$1.Description,
|
|
1713
|
-
{
|
|
1714
|
-
"data-slot": "dialog-description",
|
|
1715
|
-
className: cn(
|
|
1716
|
-
"mt-0.5 text-sm leading-relaxed text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
1717
|
-
className
|
|
1718
|
-
),
|
|
1719
|
-
...props
|
|
1720
|
-
}
|
|
1721
|
-
);
|
|
1722
|
-
}
|
|
1723
1969
|
function splitChangeLines(change) {
|
|
1724
1970
|
const v = change.value;
|
|
1725
1971
|
if (v === "") return [];
|
|
@@ -5886,6 +6132,32 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
5886
6132
|
}
|
|
5887
6133
|
return entries;
|
|
5888
6134
|
}
|
|
6135
|
+
function groupBrowserActivityEntries(entries) {
|
|
6136
|
+
const grouped = [];
|
|
6137
|
+
let buffer = [];
|
|
6138
|
+
const flush = () => {
|
|
6139
|
+
if (buffer.length === 0) return;
|
|
6140
|
+
grouped.push({
|
|
6141
|
+
kind: "browser_activity",
|
|
6142
|
+
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
6143
|
+
calls: buffer
|
|
6144
|
+
});
|
|
6145
|
+
buffer = [];
|
|
6146
|
+
};
|
|
6147
|
+
for (const entry of entries) {
|
|
6148
|
+
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
6149
|
+
buffer.push(entry.tc);
|
|
6150
|
+
continue;
|
|
6151
|
+
}
|
|
6152
|
+
flush();
|
|
6153
|
+
grouped.push(entry);
|
|
6154
|
+
}
|
|
6155
|
+
flush();
|
|
6156
|
+
return grouped;
|
|
6157
|
+
}
|
|
6158
|
+
function isBrowserToolCall(call) {
|
|
6159
|
+
return call.toolName.startsWith("browser_");
|
|
6160
|
+
}
|
|
5889
6161
|
function groupMessages(messages) {
|
|
5890
6162
|
const groups = [];
|
|
5891
6163
|
let pendingSystem = [];
|
|
@@ -6042,6 +6314,15 @@ function TimelineEntryItem({
|
|
|
6042
6314
|
] }) })
|
|
6043
6315
|
] });
|
|
6044
6316
|
}
|
|
6317
|
+
if (entry.kind === "browser_activity") {
|
|
6318
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
6319
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
6320
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
6321
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
6322
|
+
] }),
|
|
6323
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
6324
|
+
] });
|
|
6325
|
+
}
|
|
6045
6326
|
if (entry.kind === "text") {
|
|
6046
6327
|
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
6047
6328
|
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
@@ -6103,11 +6384,12 @@ function AssistantGroup({
|
|
|
6103
6384
|
onFileSelect,
|
|
6104
6385
|
onRetry
|
|
6105
6386
|
}) {
|
|
6106
|
-
|
|
6387
|
+
let entries = [];
|
|
6107
6388
|
for (let i = 0; i < messages.length; i++) {
|
|
6108
6389
|
const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
|
|
6109
6390
|
entries.push(...messageToEntries(messages[i], isLast, artifactFallbacks));
|
|
6110
6391
|
}
|
|
6392
|
+
entries = groupBrowserActivityEntries(entries);
|
|
6111
6393
|
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
6112
6394
|
const lastEntry = entries[entries.length - 1];
|
|
6113
6395
|
const hasRunningTool = entries.some(
|
|
@@ -7175,6 +7457,7 @@ function WorkspacePanel({
|
|
|
7175
7457
|
return /* @__PURE__ */ jsx(
|
|
7176
7458
|
"aside",
|
|
7177
7459
|
{
|
|
7460
|
+
"data-testid": "workspace-panel",
|
|
7178
7461
|
role: "button",
|
|
7179
7462
|
tabIndex: 0,
|
|
7180
7463
|
className: "relative z-10 flex min-h-0 w-10 shrink-0 cursor-pointer items-center justify-center border-l border-muted-foreground/20 bg-card text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/30",
|
|
@@ -7193,6 +7476,7 @@ function WorkspacePanel({
|
|
|
7193
7476
|
return /* @__PURE__ */ jsxs(
|
|
7194
7477
|
"aside",
|
|
7195
7478
|
{
|
|
7479
|
+
"data-testid": "workspace-panel",
|
|
7196
7480
|
className: "relative z-10 flex min-h-0 flex-col overflow-hidden border-l border-muted-foreground/20 bg-card",
|
|
7197
7481
|
style: { width, minWidth: MIN_WIDTH, maxWidth: MAX_WIDTH },
|
|
7198
7482
|
children: [
|
|
@@ -7434,6 +7718,10 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
7434
7718
|
"expert.override",
|
|
7435
7719
|
"artifact.created",
|
|
7436
7720
|
"artifact.updated",
|
|
7721
|
+
"browser.provisioned",
|
|
7722
|
+
"browser.destroyed",
|
|
7723
|
+
"browser.control_granted",
|
|
7724
|
+
"browser.control_returned",
|
|
7437
7725
|
"clarify.response"
|
|
7438
7726
|
];
|
|
7439
7727
|
|
|
@@ -7458,7 +7746,8 @@ function createInitialAgentChatState(options = {}) {
|
|
|
7458
7746
|
sessionDone: false,
|
|
7459
7747
|
hadDeltas: false,
|
|
7460
7748
|
terminal: false,
|
|
7461
|
-
workspaceRefreshKey: 0
|
|
7749
|
+
workspaceRefreshKey: 0,
|
|
7750
|
+
browser: null
|
|
7462
7751
|
};
|
|
7463
7752
|
}
|
|
7464
7753
|
function applyAgentChatEvent(state, event) {
|
|
@@ -7482,7 +7771,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7482
7771
|
{
|
|
7483
7772
|
id: `evt-${event.eventId}`,
|
|
7484
7773
|
role: "system",
|
|
7485
|
-
content:
|
|
7774
|
+
content: stringValue2(event.data.skill),
|
|
7486
7775
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7487
7776
|
status: "complete",
|
|
7488
7777
|
systemKind: "skill_invoked",
|
|
@@ -7499,7 +7788,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7499
7788
|
{
|
|
7500
7789
|
id: `evt-${event.eventId}`,
|
|
7501
7790
|
role: "system",
|
|
7502
|
-
content:
|
|
7791
|
+
content: stringValue2(event.data.name),
|
|
7503
7792
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7504
7793
|
status: "complete",
|
|
7505
7794
|
systemKind: "artifact",
|
|
@@ -7512,6 +7801,23 @@ function applyAgentChatEvent(state, event) {
|
|
|
7512
7801
|
}
|
|
7513
7802
|
}
|
|
7514
7803
|
]);
|
|
7804
|
+
case "browser.provisioned":
|
|
7805
|
+
return applyBrowserEvent(nextState, event, {
|
|
7806
|
+
status: "live",
|
|
7807
|
+
controlOwner: null
|
|
7808
|
+
});
|
|
7809
|
+
case "browser.control_granted":
|
|
7810
|
+
return applyBrowserEvent(nextState, event, {
|
|
7811
|
+
status: "user-control",
|
|
7812
|
+
controlOwner: stringValue2(event.data.owner_user_id) || null
|
|
7813
|
+
});
|
|
7814
|
+
case "browser.control_returned":
|
|
7815
|
+
return applyBrowserEvent(nextState, event, {
|
|
7816
|
+
status: "live",
|
|
7817
|
+
controlOwner: null
|
|
7818
|
+
});
|
|
7819
|
+
case "browser.destroyed":
|
|
7820
|
+
return applyBrowserEvent(nextState, event, null);
|
|
7515
7821
|
case "llm.delta":
|
|
7516
7822
|
return applyLlmDelta(nextState, event);
|
|
7517
7823
|
case "llm.response":
|
|
@@ -7521,7 +7827,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7521
7827
|
case "tool.call":
|
|
7522
7828
|
return applyToolCall(nextState, event);
|
|
7523
7829
|
case "tool.result": {
|
|
7524
|
-
const toolCallId =
|
|
7830
|
+
const toolCallId = stringValue2(event.data.tool_call_id);
|
|
7525
7831
|
const toolName = findToolNameById(nextState.messages, toolCallId);
|
|
7526
7832
|
const messages = applyToolResult(nextState.messages, event.data);
|
|
7527
7833
|
const mutatesWorkspace = toolName !== null && WORKSPACE_MUTATING_TOOLS.has(toolName);
|
|
@@ -7591,8 +7897,8 @@ function applyRetryIndicator(state, event) {
|
|
|
7591
7897
|
case "session.done":
|
|
7592
7898
|
return { ...state, retryIndicator: null };
|
|
7593
7899
|
case "harness.crash": {
|
|
7594
|
-
const title =
|
|
7595
|
-
const detail =
|
|
7900
|
+
const title = stringValue2(event.data.error_title) || "A transient error occurred, retrying...";
|
|
7901
|
+
const detail = stringValue2(event.data.error_detail) || stringValue2(event.data.error);
|
|
7596
7902
|
return {
|
|
7597
7903
|
...state,
|
|
7598
7904
|
retryIndicator: {
|
|
@@ -7607,7 +7913,7 @@ function applyRetryIndicator(state, event) {
|
|
|
7607
7913
|
}
|
|
7608
7914
|
}
|
|
7609
7915
|
function applyUserMessage(messages, eventId, data) {
|
|
7610
|
-
const content =
|
|
7916
|
+
const content = stringValue2(data.content);
|
|
7611
7917
|
const next = [...messages];
|
|
7612
7918
|
const localIdx = next.findIndex(
|
|
7613
7919
|
(m) => m.role === "user" && m.id.startsWith("local-") && m.content === content
|
|
@@ -7625,9 +7931,47 @@ function applyUserMessage(messages, eventId, data) {
|
|
|
7625
7931
|
});
|
|
7626
7932
|
return next;
|
|
7627
7933
|
}
|
|
7934
|
+
function applyBrowserEvent(state, event, browser) {
|
|
7935
|
+
return withMessages(
|
|
7936
|
+
{ ...state, browser },
|
|
7937
|
+
[...state.messages, browserMarker(event)]
|
|
7938
|
+
);
|
|
7939
|
+
}
|
|
7940
|
+
function browserMarker(event) {
|
|
7941
|
+
const labels = {
|
|
7942
|
+
"browser.provisioned": {
|
|
7943
|
+
content: "Browser ready.",
|
|
7944
|
+
warning: false
|
|
7945
|
+
},
|
|
7946
|
+
"browser.control_granted": {
|
|
7947
|
+
content: "A user took control of the browser.",
|
|
7948
|
+
warning: true
|
|
7949
|
+
},
|
|
7950
|
+
"browser.control_returned": {
|
|
7951
|
+
content: "Browser control returned to the agent.",
|
|
7952
|
+
warning: false
|
|
7953
|
+
},
|
|
7954
|
+
"browser.destroyed": {
|
|
7955
|
+
content: "Browser closed.",
|
|
7956
|
+
warning: false
|
|
7957
|
+
}
|
|
7958
|
+
};
|
|
7959
|
+
const label = labels[event.type] ?? {
|
|
7960
|
+
content: "Browser updated.",
|
|
7961
|
+
warning: false
|
|
7962
|
+
};
|
|
7963
|
+
return {
|
|
7964
|
+
id: `browser-marker-${event.eventId}`,
|
|
7965
|
+
role: "system",
|
|
7966
|
+
content: label.content,
|
|
7967
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
7968
|
+
status: "complete",
|
|
7969
|
+
systemKind: label.warning ? "browser_marker_warning" : "browser_marker"
|
|
7970
|
+
};
|
|
7971
|
+
}
|
|
7628
7972
|
function applyLlmDelta(state, event) {
|
|
7629
|
-
const deltaContent =
|
|
7630
|
-
const deltaReasoning =
|
|
7973
|
+
const deltaContent = stringValue2(event.data.content);
|
|
7974
|
+
const deltaReasoning = stringValue2(event.data.reasoning);
|
|
7631
7975
|
const messages = [...state.messages];
|
|
7632
7976
|
const lastIdx = findLastAssistantIndex(messages);
|
|
7633
7977
|
const lastMsg = lastIdx >= 0 ? messages[lastIdx] : null;
|
|
@@ -7664,7 +8008,7 @@ function applyLlmDelta(state, event) {
|
|
|
7664
8008
|
function applyLlmResponse(state, event) {
|
|
7665
8009
|
const messages = [...state.messages];
|
|
7666
8010
|
const message = objectValue(event.data.message);
|
|
7667
|
-
const responseContent =
|
|
8011
|
+
const responseContent = stringValue2(message?.content) || stringValue2(event.data.content);
|
|
7668
8012
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
7669
8013
|
const hasToolCalls = toolCalls.length > 0;
|
|
7670
8014
|
const idx = findLastAssistantIndex(messages);
|
|
@@ -7722,12 +8066,12 @@ function applyLlmResponse(state, event) {
|
|
|
7722
8066
|
cachedInputTokens: numberValue(event.data.cache_read_tokens),
|
|
7723
8067
|
totalTokens: inputTokens + outputTokens,
|
|
7724
8068
|
contextWindow: numberValue(event.data.context_window),
|
|
7725
|
-
model:
|
|
8069
|
+
model: stringValue2(event.data.model)
|
|
7726
8070
|
}
|
|
7727
8071
|
};
|
|
7728
8072
|
}
|
|
7729
8073
|
function applyLlmThinking(state, event) {
|
|
7730
|
-
const reasoningText =
|
|
8074
|
+
const reasoningText = stringValue2(event.data.reasoning) || stringValue2(event.data.content);
|
|
7731
8075
|
const messages = [...state.messages];
|
|
7732
8076
|
const idx = findLastAssistantIndex(messages);
|
|
7733
8077
|
const prev = idx >= 0 ? messages[idx] : null;
|
|
@@ -7775,11 +8119,11 @@ function applyToolCall(state, event) {
|
|
|
7775
8119
|
messages[assistantIdx] = assistant;
|
|
7776
8120
|
}
|
|
7777
8121
|
const existingCalls = assistant.toolCalls ?? [];
|
|
7778
|
-
const toolCallId =
|
|
8122
|
+
const toolCallId = stringValue2(event.data.tool_call_id) || `tc-${event.eventId}`;
|
|
7779
8123
|
if (!existingCalls.some((tc) => tc.id === toolCallId)) {
|
|
7780
8124
|
const entry = {
|
|
7781
8125
|
id: toolCallId,
|
|
7782
|
-
toolName:
|
|
8126
|
+
toolName: stringValue2(event.data.name) || stringValue2(event.data.tool_name) || "unknown",
|
|
7783
8127
|
args: typeof event.data.arguments === "string" ? event.data.arguments : JSON.stringify(event.data.arguments ?? {}),
|
|
7784
8128
|
status: "running"
|
|
7785
8129
|
};
|
|
@@ -7795,7 +8139,7 @@ function applyToolCall(state, event) {
|
|
|
7795
8139
|
};
|
|
7796
8140
|
}
|
|
7797
8141
|
function applyToolResult(messages, data) {
|
|
7798
|
-
const targetId =
|
|
8142
|
+
const targetId = stringValue2(data.tool_call_id);
|
|
7799
8143
|
let matchIdx = -1;
|
|
7800
8144
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
7801
8145
|
if (messages[i]?.role === "assistant" && messages[i]?.toolCalls?.some((tc) => tc.id === targetId)) {
|
|
@@ -7864,8 +8208,8 @@ function buildErrorInfo(event) {
|
|
|
7864
8208
|
}
|
|
7865
8209
|
return {
|
|
7866
8210
|
category: event.data.error_category,
|
|
7867
|
-
title:
|
|
7868
|
-
detail:
|
|
8211
|
+
title: stringValue2(event.data.error_title) || "The session failed due to an internal error.",
|
|
8212
|
+
detail: stringValue2(event.data.error_detail) || stringValue2(event.data.error),
|
|
7869
8213
|
retryable: Boolean(event.data.retryable)
|
|
7870
8214
|
};
|
|
7871
8215
|
}
|
|
@@ -7909,7 +8253,7 @@ function applyExpertFeedback(messages, type, data) {
|
|
|
7909
8253
|
return messages;
|
|
7910
8254
|
}
|
|
7911
8255
|
function applyClarifyResponse(messages, data) {
|
|
7912
|
-
const targetToolId =
|
|
8256
|
+
const targetToolId = stringValue2(data.tool_call_id);
|
|
7913
8257
|
const responses = Array.isArray(data.responses) ? data.responses : void 0;
|
|
7914
8258
|
if (!targetToolId || !responses) return messages;
|
|
7915
8259
|
const next = [...messages];
|
|
@@ -7924,8 +8268,8 @@ function applyClarifyResponse(messages, data) {
|
|
|
7924
8268
|
clarifyAnswers: responses.map((response) => {
|
|
7925
8269
|
const row = objectValue(response) ?? {};
|
|
7926
8270
|
return {
|
|
7927
|
-
question:
|
|
7928
|
-
answer:
|
|
8271
|
+
question: stringValue2(row.question),
|
|
8272
|
+
answer: stringValue2(row.answer),
|
|
7929
8273
|
is_other: Boolean(row.is_other)
|
|
7930
8274
|
};
|
|
7931
8275
|
})
|
|
@@ -7945,7 +8289,7 @@ function applyPolicyDenied(state, data) {
|
|
|
7945
8289
|
...policyMsg,
|
|
7946
8290
|
content: `${policyMsg.content}
|
|
7947
8291
|
|
|
7948
|
-
**Policy denied**: ${
|
|
8292
|
+
**Policy denied**: ${stringValue2(data.reason) || "Action blocked by governance policy."}`,
|
|
7949
8293
|
status: "error"
|
|
7950
8294
|
};
|
|
7951
8295
|
}
|
|
@@ -7997,7 +8341,7 @@ function objectValue(value) {
|
|
|
7997
8341
|
}
|
|
7998
8342
|
return void 0;
|
|
7999
8343
|
}
|
|
8000
|
-
function
|
|
8344
|
+
function stringValue2(value) {
|
|
8001
8345
|
return typeof value === "string" ? value : "";
|
|
8002
8346
|
}
|
|
8003
8347
|
function numberValue(value) {
|
|
@@ -8231,6 +8575,7 @@ function useAgentChatRuntime({
|
|
|
8231
8575
|
}
|
|
8232
8576
|
}, [adapter, sessionId]);
|
|
8233
8577
|
return {
|
|
8578
|
+
state,
|
|
8234
8579
|
session,
|
|
8235
8580
|
messages: state.messages,
|
|
8236
8581
|
isRunning: state.isRunning,
|
|
@@ -8282,6 +8627,7 @@ function AgentChat({
|
|
|
8282
8627
|
const isReadOnlySession = isScheduledRunSession(runtime.session);
|
|
8283
8628
|
const effectiveDisabled = disabled || isReadOnlySession;
|
|
8284
8629
|
const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
|
|
8630
|
+
const browserState = runtime.state.browser;
|
|
8285
8631
|
useEffect(() => {
|
|
8286
8632
|
onMessagesChange?.(runtime.messages);
|
|
8287
8633
|
}, [onMessagesChange, runtime.messages]);
|
|
@@ -8318,19 +8664,29 @@ function AgentChat({
|
|
|
8318
8664
|
retryIndicator: runtime.retryIndicator
|
|
8319
8665
|
}
|
|
8320
8666
|
) }),
|
|
8321
|
-
/* @__PURE__ */
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8667
|
+
/* @__PURE__ */ jsxs("div", { "data-testid": "right-stack", className: "flex min-h-0 shrink-0 flex-col", children: [
|
|
8668
|
+
browserState !== null && sessionId && /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 border-b border-line", children: /* @__PURE__ */ jsx(
|
|
8669
|
+
BrowserPane,
|
|
8670
|
+
{
|
|
8671
|
+
sessionId,
|
|
8672
|
+
state: browserState,
|
|
8673
|
+
adapter
|
|
8674
|
+
}
|
|
8675
|
+
) }),
|
|
8676
|
+
/* @__PURE__ */ jsx(
|
|
8677
|
+
WorkspacePanel,
|
|
8678
|
+
{
|
|
8679
|
+
adapter,
|
|
8680
|
+
sessionId,
|
|
8681
|
+
selectedPath: workspacePath,
|
|
8682
|
+
onSelectedPathChange: setWorkspacePath,
|
|
8683
|
+
collapsed: workspaceCollapsed,
|
|
8684
|
+
onCollapsedChange: setWorkspaceCollapsed,
|
|
8685
|
+
refreshSignal: runtime.workspaceRefreshKey,
|
|
8686
|
+
disabled: effectiveDisabled
|
|
8687
|
+
}
|
|
8688
|
+
)
|
|
8689
|
+
] })
|
|
8334
8690
|
] }) })
|
|
8335
8691
|
}
|
|
8336
8692
|
);
|