@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.cjs
CHANGED
|
@@ -6,9 +6,9 @@ var react = require('react');
|
|
|
6
6
|
var auto = require('chart.js/auto');
|
|
7
7
|
var nextThemes = require('next-themes');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
+
var lucideReact = require('lucide-react');
|
|
9
10
|
var classVarianceAuthority = require('class-variance-authority');
|
|
10
11
|
var radixUi = require('radix-ui');
|
|
11
|
-
var lucideReact = require('lucide-react');
|
|
12
12
|
var useStickToBottom = require('use-stick-to-bottom');
|
|
13
13
|
var cjk = require('@streamdown/cjk');
|
|
14
14
|
var code = require('@streamdown/code');
|
|
@@ -263,77 +263,218 @@ function Button({
|
|
|
263
263
|
}
|
|
264
264
|
);
|
|
265
265
|
}
|
|
266
|
+
function BrowserControlBar({
|
|
267
|
+
sessionId,
|
|
268
|
+
hasControl,
|
|
269
|
+
adapter
|
|
270
|
+
}) {
|
|
271
|
+
const [pending, setPending] = react.useState(false);
|
|
272
|
+
const [error, setError] = react.useState(null);
|
|
273
|
+
async function toggleControl() {
|
|
274
|
+
if (!sessionId || pending) return;
|
|
275
|
+
setPending(true);
|
|
276
|
+
setError(null);
|
|
277
|
+
try {
|
|
278
|
+
if (hasControl) {
|
|
279
|
+
await adapter.releaseBrowserControl(sessionId);
|
|
280
|
+
} else {
|
|
281
|
+
await adapter.acquireBrowserControl(sessionId);
|
|
282
|
+
}
|
|
283
|
+
} catch (nextError) {
|
|
284
|
+
setError(nextError.message);
|
|
285
|
+
} finally {
|
|
286
|
+
setPending(false);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-11 items-center gap-2 border-t border-line bg-card px-3 py-2", children: [
|
|
290
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
291
|
+
Button,
|
|
292
|
+
{
|
|
293
|
+
type: "button",
|
|
294
|
+
size: "xs",
|
|
295
|
+
variant: hasControl ? "secondary" : "default",
|
|
296
|
+
disabled: !sessionId || pending,
|
|
297
|
+
onClick: () => void toggleControl(),
|
|
298
|
+
children: [
|
|
299
|
+
hasControl ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcwIcon, { className: "size-3", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MousePointer2Icon, { className: "size-3", "aria-hidden": "true" }),
|
|
300
|
+
hasControl ? "Return control" : "Take control"
|
|
301
|
+
]
|
|
302
|
+
}
|
|
303
|
+
),
|
|
304
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
|
|
305
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 rounded-full bg-red-500", "aria-hidden": "true" }),
|
|
306
|
+
"Live"
|
|
307
|
+
] }),
|
|
308
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-40 truncate text-[11px] text-destructive", children: error })
|
|
309
|
+
] });
|
|
310
|
+
}
|
|
311
|
+
function BrowserLiveView({
|
|
312
|
+
src,
|
|
313
|
+
testId = "browser-iframe"
|
|
314
|
+
}) {
|
|
315
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
316
|
+
"iframe",
|
|
317
|
+
{
|
|
318
|
+
"data-testid": testId,
|
|
319
|
+
title: "Browser live view",
|
|
320
|
+
src,
|
|
321
|
+
className: "h-full w-full border-0 bg-black",
|
|
322
|
+
allow: "clipboard-read; clipboard-write"
|
|
323
|
+
}
|
|
324
|
+
);
|
|
325
|
+
}
|
|
266
326
|
|
|
267
|
-
// src/components/
|
|
327
|
+
// src/components/browser/browser-status-dot.tsx
|
|
268
328
|
init_utils();
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
329
|
+
function BrowserStatusDot({
|
|
330
|
+
status
|
|
331
|
+
}) {
|
|
332
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
333
|
+
"span",
|
|
334
|
+
{
|
|
335
|
+
"aria-hidden": "true",
|
|
336
|
+
className: cn(
|
|
337
|
+
"inline-block size-2 shrink-0 rounded-full",
|
|
338
|
+
status === "live" && "bg-emerald-500",
|
|
339
|
+
status === "user-control" && "bg-amber-500",
|
|
340
|
+
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
341
|
+
status === "closed" && "bg-muted-foreground"
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/components/ui/dialog.tsx
|
|
348
|
+
init_utils();
|
|
349
|
+
function Dialog({
|
|
350
|
+
...props
|
|
351
|
+
}) {
|
|
352
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
353
|
+
}
|
|
354
|
+
function DialogPortal({
|
|
355
|
+
...props
|
|
356
|
+
}) {
|
|
357
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Portal, { "data-slot": "dialog-portal", ...props });
|
|
358
|
+
}
|
|
359
|
+
function DialogOverlay({
|
|
280
360
|
className,
|
|
281
361
|
...props
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
362
|
+
}) {
|
|
363
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
364
|
+
radixUi.Dialog.Overlay,
|
|
365
|
+
{
|
|
366
|
+
"data-slot": "dialog-overlay",
|
|
367
|
+
className: cn(
|
|
368
|
+
"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",
|
|
369
|
+
className
|
|
370
|
+
),
|
|
371
|
+
...props
|
|
372
|
+
}
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
function DialogContent({
|
|
290
376
|
className,
|
|
291
|
-
title = "No messages yet",
|
|
292
|
-
description = "Start a conversation to see messages here",
|
|
293
|
-
icon,
|
|
294
377
|
children,
|
|
378
|
+
showCloseButton = true,
|
|
295
379
|
...props
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
380
|
+
}) {
|
|
381
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
|
|
382
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
383
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
384
|
+
radixUi.Dialog.Content,
|
|
385
|
+
{
|
|
386
|
+
"data-slot": "dialog-content",
|
|
387
|
+
className: cn(
|
|
388
|
+
"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",
|
|
389
|
+
className
|
|
390
|
+
),
|
|
391
|
+
...props,
|
|
392
|
+
children: [
|
|
393
|
+
children,
|
|
394
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
395
|
+
Button,
|
|
396
|
+
{
|
|
397
|
+
variant: "ghost",
|
|
398
|
+
className: "absolute top-5 right-5 bg-secondary",
|
|
399
|
+
size: "icon-sm",
|
|
400
|
+
children: [
|
|
401
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
402
|
+
lucideReact.XIcon,
|
|
403
|
+
{}
|
|
404
|
+
),
|
|
405
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
) })
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
] });
|
|
413
|
+
}
|
|
414
|
+
function DialogHeader({ className, ...props }) {
|
|
415
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
416
|
+
"div",
|
|
417
|
+
{
|
|
418
|
+
"data-slot": "dialog-header",
|
|
419
|
+
className: cn("flex flex-col gap-2", className),
|
|
420
|
+
...props
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
function DialogFooter({
|
|
314
425
|
className,
|
|
426
|
+
showCloseButton = false,
|
|
427
|
+
children,
|
|
315
428
|
...props
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
scrollToBottom();
|
|
320
|
-
}, [scrollToBottom]);
|
|
321
|
-
return !isAtBottom && /* @__PURE__ */ jsxRuntime.jsx(
|
|
322
|
-
Button,
|
|
429
|
+
}) {
|
|
430
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
431
|
+
"div",
|
|
323
432
|
{
|
|
433
|
+
"data-slot": "dialog-footer",
|
|
324
434
|
className: cn(
|
|
325
|
-
"
|
|
435
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
326
436
|
className
|
|
327
437
|
),
|
|
328
|
-
onClick: handleScrollToBottom,
|
|
329
|
-
size: "icon",
|
|
330
|
-
type: "button",
|
|
331
|
-
variant: "outline",
|
|
332
438
|
...props,
|
|
333
|
-
children:
|
|
439
|
+
children: [
|
|
440
|
+
children,
|
|
441
|
+
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", children: "Close" }) })
|
|
442
|
+
]
|
|
334
443
|
}
|
|
335
444
|
);
|
|
336
|
-
}
|
|
445
|
+
}
|
|
446
|
+
function DialogTitle({
|
|
447
|
+
className,
|
|
448
|
+
...props
|
|
449
|
+
}) {
|
|
450
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
451
|
+
radixUi.Dialog.Title,
|
|
452
|
+
{
|
|
453
|
+
"data-slot": "dialog-title",
|
|
454
|
+
className: cn(
|
|
455
|
+
"font-heading text-lg leading-none font-semibold tracking-wider uppercase",
|
|
456
|
+
className
|
|
457
|
+
),
|
|
458
|
+
...props
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
function DialogDescription({
|
|
463
|
+
className,
|
|
464
|
+
...props
|
|
465
|
+
}) {
|
|
466
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
467
|
+
radixUi.Dialog.Description,
|
|
468
|
+
{
|
|
469
|
+
"data-slot": "dialog-description",
|
|
470
|
+
className: cn(
|
|
471
|
+
"mt-0.5 text-sm leading-relaxed text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
472
|
+
className
|
|
473
|
+
),
|
|
474
|
+
...props
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
}
|
|
337
478
|
|
|
338
479
|
// src/components/ui/tooltip.tsx
|
|
339
480
|
init_utils();
|
|
@@ -365,24 +506,190 @@ function TooltipContent({
|
|
|
365
506
|
sideOffset = 0,
|
|
366
507
|
children,
|
|
367
508
|
...props
|
|
368
|
-
}) {
|
|
369
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
370
|
-
radixUi.Tooltip.Content,
|
|
509
|
+
}) {
|
|
510
|
+
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
511
|
+
radixUi.Tooltip.Content,
|
|
512
|
+
{
|
|
513
|
+
"data-slot": "tooltip-content",
|
|
514
|
+
sideOffset,
|
|
515
|
+
className: cn(
|
|
516
|
+
"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",
|
|
517
|
+
className
|
|
518
|
+
),
|
|
519
|
+
...props,
|
|
520
|
+
children: [
|
|
521
|
+
children,
|
|
522
|
+
/* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-none bg-foreground fill-foreground" })
|
|
523
|
+
]
|
|
524
|
+
}
|
|
525
|
+
) });
|
|
526
|
+
}
|
|
527
|
+
function BrowserPane({ sessionId, state, adapter }) {
|
|
528
|
+
const [fullscreenOpen, setFullscreenOpen] = react.useState(false);
|
|
529
|
+
const [inlinePreviewOpen, setInlinePreviewOpen] = react.useState(false);
|
|
530
|
+
const hasLiveViewAdapter = typeof adapter.browserLiveViewUrl === "function";
|
|
531
|
+
const hasControlAdapter = typeof adapter.acquireBrowserControl === "function" && typeof adapter.releaseBrowserControl === "function";
|
|
532
|
+
const liveViewUrl = react.useMemo(() => {
|
|
533
|
+
if (!hasLiveViewAdapter) return "";
|
|
534
|
+
return adapter.browserLiveViewUrl(sessionId);
|
|
535
|
+
}, [adapter, hasLiveViewAdapter, sessionId]);
|
|
536
|
+
const hasLiveView = state.status !== "provisioning" && state.status !== "closed";
|
|
537
|
+
const canOpenFullscreen = hasLiveView && Boolean(liveViewUrl);
|
|
538
|
+
react.useEffect(() => {
|
|
539
|
+
setFullscreenOpen(false);
|
|
540
|
+
setInlinePreviewOpen(false);
|
|
541
|
+
}, [sessionId]);
|
|
542
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
543
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
544
|
+
"div",
|
|
545
|
+
{
|
|
546
|
+
"data-testid": "browser-pane",
|
|
547
|
+
className: "flex h-full min-h-0 flex-col bg-background",
|
|
548
|
+
children: [
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex min-h-10 items-center gap-2 border-b border-line bg-card px-3 text-xs text-foreground", children: [
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZapIcon, { className: "size-3.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
551
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Browser" }),
|
|
552
|
+
/* @__PURE__ */ jsxRuntime.jsx(BrowserStatusDot, { status: state.status }),
|
|
553
|
+
state.controlOwner && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate text-amber-500", children: [
|
|
554
|
+
state.controlOwner,
|
|
555
|
+
" has control"
|
|
556
|
+
] }),
|
|
557
|
+
canOpenFullscreen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-auto flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
559
|
+
"button",
|
|
560
|
+
{
|
|
561
|
+
type: "button",
|
|
562
|
+
"aria-label": "Maximize browser",
|
|
563
|
+
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",
|
|
564
|
+
onClick: () => setFullscreenOpen(true),
|
|
565
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2Icon, { className: "size-3.5", "aria-hidden": "true" })
|
|
566
|
+
}
|
|
567
|
+
) }),
|
|
568
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "bottom", children: "Full screen" })
|
|
569
|
+
] }) }) })
|
|
570
|
+
] }),
|
|
571
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 bg-black", children: state.status === "provisioning" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Starting browser..." }) : state.status === "closed" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser closed." }) : liveViewUrl && inlinePreviewOpen ? /* @__PURE__ */ jsxRuntime.jsx(BrowserLiveView, { src: liveViewUrl }) : liveViewUrl ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
572
|
+
"button",
|
|
573
|
+
{
|
|
574
|
+
type: "button",
|
|
575
|
+
"aria-label": "Open browser live preview",
|
|
576
|
+
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",
|
|
577
|
+
onClick: () => setInlinePreviewOpen(true),
|
|
578
|
+
children: [
|
|
579
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PlayIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
580
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Open live preview" })
|
|
581
|
+
]
|
|
582
|
+
}
|
|
583
|
+
) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser live view is unavailable." }) }),
|
|
584
|
+
hasLiveView && hasControlAdapter && /* @__PURE__ */ jsxRuntime.jsx(
|
|
585
|
+
BrowserControlBar,
|
|
586
|
+
{
|
|
587
|
+
sessionId,
|
|
588
|
+
hasControl: state.status === "user-control",
|
|
589
|
+
adapter
|
|
590
|
+
}
|
|
591
|
+
)
|
|
592
|
+
]
|
|
593
|
+
}
|
|
594
|
+
),
|
|
595
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: fullscreenOpen, onOpenChange: setFullscreenOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
596
|
+
DialogContent,
|
|
597
|
+
{
|
|
598
|
+
"aria-describedby": void 0,
|
|
599
|
+
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",
|
|
600
|
+
children: [
|
|
601
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "h-10 shrink-0 flex-row items-center gap-2 border-b border-line bg-card px-4 py-0", children: [
|
|
602
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZapIcon, { className: "size-3.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
603
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-xs normal-case tracking-normal", children: "Browser" }),
|
|
604
|
+
/* @__PURE__ */ jsxRuntime.jsx(BrowserStatusDot, { status: state.status }),
|
|
605
|
+
state.controlOwner && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate text-xs text-amber-500", children: [
|
|
606
|
+
state.controlOwner,
|
|
607
|
+
" has control"
|
|
608
|
+
] })
|
|
609
|
+
] }),
|
|
610
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 bg-black", children: liveViewUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
611
|
+
BrowserLiveView,
|
|
612
|
+
{
|
|
613
|
+
src: liveViewUrl,
|
|
614
|
+
testId: "browser-fullscreen-iframe"
|
|
615
|
+
}
|
|
616
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center bg-background text-sm text-muted-foreground", children: "Browser live view is unavailable." }) })
|
|
617
|
+
]
|
|
618
|
+
}
|
|
619
|
+
) })
|
|
620
|
+
] });
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/components/ai-elements/conversation.tsx
|
|
624
|
+
init_utils();
|
|
625
|
+
var Conversation = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
626
|
+
useStickToBottom.StickToBottom,
|
|
627
|
+
{
|
|
628
|
+
className: cn("relative flex-1", className),
|
|
629
|
+
initial: "smooth",
|
|
630
|
+
resize: "smooth",
|
|
631
|
+
role: "log",
|
|
632
|
+
...props
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
var ConversationContent = ({
|
|
636
|
+
className,
|
|
637
|
+
...props
|
|
638
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
639
|
+
useStickToBottom.StickToBottom.Content,
|
|
640
|
+
{
|
|
641
|
+
className: cn("flex flex-col gap-6 py-6 px-6", className),
|
|
642
|
+
...props
|
|
643
|
+
}
|
|
644
|
+
);
|
|
645
|
+
var ConversationEmptyState = ({
|
|
646
|
+
className,
|
|
647
|
+
title = "No messages yet",
|
|
648
|
+
description = "Start a conversation to see messages here",
|
|
649
|
+
icon,
|
|
650
|
+
children,
|
|
651
|
+
...props
|
|
652
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
653
|
+
"div",
|
|
654
|
+
{
|
|
655
|
+
className: cn(
|
|
656
|
+
"flex size-full flex-col items-center justify-center gap-4 p-8 text-center",
|
|
657
|
+
className
|
|
658
|
+
),
|
|
659
|
+
...props,
|
|
660
|
+
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
661
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center size-14 rounded-2xl bg-muted/60 text-muted-foreground/60", children: icon }),
|
|
662
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
|
|
663
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-base text-foreground/80", children: title }),
|
|
664
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground/60 text-sm max-w-sm", children: description })
|
|
665
|
+
] })
|
|
666
|
+
] })
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
var ConversationScrollButton = ({
|
|
670
|
+
className,
|
|
671
|
+
...props
|
|
672
|
+
}) => {
|
|
673
|
+
const { isAtBottom, scrollToBottom } = useStickToBottom.useStickToBottomContext();
|
|
674
|
+
const handleScrollToBottom = react.useCallback(() => {
|
|
675
|
+
scrollToBottom();
|
|
676
|
+
}, [scrollToBottom]);
|
|
677
|
+
return !isAtBottom && /* @__PURE__ */ jsxRuntime.jsx(
|
|
678
|
+
Button,
|
|
371
679
|
{
|
|
372
|
-
"data-slot": "tooltip-content",
|
|
373
|
-
sideOffset,
|
|
374
680
|
className: cn(
|
|
375
|
-
"
|
|
681
|
+
"absolute bottom-4 left-[50%] translate-x-[-50%] rounded-full shadow-lg border-border/50 dark:bg-background dark:hover:bg-muted",
|
|
376
682
|
className
|
|
377
683
|
),
|
|
684
|
+
onClick: handleScrollToBottom,
|
|
685
|
+
size: "icon",
|
|
686
|
+
type: "button",
|
|
687
|
+
variant: "outline",
|
|
378
688
|
...props,
|
|
379
|
-
children:
|
|
380
|
-
children,
|
|
381
|
-
/* @__PURE__ */ jsxRuntime.jsx(radixUi.Tooltip.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-none bg-foreground fill-foreground" })
|
|
382
|
-
]
|
|
689
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownIcon, { className: "size-4" })
|
|
383
690
|
}
|
|
384
|
-
)
|
|
385
|
-
}
|
|
691
|
+
);
|
|
692
|
+
};
|
|
386
693
|
|
|
387
694
|
// src/components/ai-elements/message.tsx
|
|
388
695
|
init_utils();
|
|
@@ -767,6 +1074,80 @@ function TimelineSeparator({
|
|
|
767
1074
|
}
|
|
768
1075
|
);
|
|
769
1076
|
}
|
|
1077
|
+
function BrowserActivityGroup({ calls }) {
|
|
1078
|
+
const [open, setOpen] = react.useState(false);
|
|
1079
|
+
const latest = calls[calls.length - 1];
|
|
1080
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-none border border-line bg-card text-xs", children: [
|
|
1081
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1082
|
+
"button",
|
|
1083
|
+
{
|
|
1084
|
+
type: "button",
|
|
1085
|
+
onClick: () => setOpen((current) => !current),
|
|
1086
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted/40",
|
|
1087
|
+
children: [
|
|
1088
|
+
open ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }),
|
|
1089
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZapIcon, { className: "size-3 shrink-0 text-amber-500", "aria-hidden": "true" }),
|
|
1090
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "browser" }),
|
|
1091
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 truncate text-muted-foreground", children: [
|
|
1092
|
+
"(",
|
|
1093
|
+
calls.length,
|
|
1094
|
+
" ",
|
|
1095
|
+
calls.length === 1 ? "action" : "actions",
|
|
1096
|
+
" - latest:",
|
|
1097
|
+
" ",
|
|
1098
|
+
latest ? summarise(latest) : "none",
|
|
1099
|
+
")"
|
|
1100
|
+
] })
|
|
1101
|
+
]
|
|
1102
|
+
}
|
|
1103
|
+
),
|
|
1104
|
+
open && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "border-t border-line py-1", children: calls.map((call) => {
|
|
1105
|
+
const error = stringValue(parseJson(call.result).error);
|
|
1106
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1107
|
+
"li",
|
|
1108
|
+
{
|
|
1109
|
+
className: "flex items-center gap-2 px-6 py-1 font-mono text-[11px]",
|
|
1110
|
+
children: [
|
|
1111
|
+
error && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1112
|
+
lucideReact.AlertCircleIcon,
|
|
1113
|
+
{
|
|
1114
|
+
"data-testid": `activity-error-${call.id}`,
|
|
1115
|
+
className: "size-3 shrink-0 text-destructive",
|
|
1116
|
+
"aria-hidden": "true"
|
|
1117
|
+
}
|
|
1118
|
+
),
|
|
1119
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: summarise(call) }),
|
|
1120
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto max-w-40 truncate text-destructive", children: error })
|
|
1121
|
+
]
|
|
1122
|
+
},
|
|
1123
|
+
call.id
|
|
1124
|
+
);
|
|
1125
|
+
}) })
|
|
1126
|
+
] });
|
|
1127
|
+
}
|
|
1128
|
+
function summarise(call) {
|
|
1129
|
+
const verb = call.toolName.replace(/^browser_/, "");
|
|
1130
|
+
const args = parseJson(call.args);
|
|
1131
|
+
const ref = stringValue(args.ref);
|
|
1132
|
+
const url = stringValue(args.url);
|
|
1133
|
+
const text = stringValue(args.text);
|
|
1134
|
+
if (url) return `${verb} ${url}`;
|
|
1135
|
+
if (ref) return `${verb} ${ref}`;
|
|
1136
|
+
if (text) return `${verb} "${text.slice(0, 24)}"`;
|
|
1137
|
+
return verb;
|
|
1138
|
+
}
|
|
1139
|
+
function parseJson(raw) {
|
|
1140
|
+
if (!raw) return {};
|
|
1141
|
+
try {
|
|
1142
|
+
const parsed = JSON.parse(raw);
|
|
1143
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
1144
|
+
} catch {
|
|
1145
|
+
return {};
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
function stringValue(value) {
|
|
1149
|
+
return typeof value === "string" ? value : "";
|
|
1150
|
+
}
|
|
770
1151
|
init_utils();
|
|
771
1152
|
|
|
772
1153
|
// src/components/chat/tools/shared.ts
|
|
@@ -1812,140 +2193,6 @@ function WebToolBlock({ tc }) {
|
|
|
1812
2193
|
displayText && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/70 truncate text-xs", children: displayText })
|
|
1813
2194
|
] });
|
|
1814
2195
|
}
|
|
1815
|
-
|
|
1816
|
-
// src/components/ui/dialog.tsx
|
|
1817
|
-
init_utils();
|
|
1818
|
-
function Dialog({
|
|
1819
|
-
...props
|
|
1820
|
-
}) {
|
|
1821
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Root, { "data-slot": "dialog", ...props });
|
|
1822
|
-
}
|
|
1823
|
-
function DialogPortal({
|
|
1824
|
-
...props
|
|
1825
|
-
}) {
|
|
1826
|
-
return /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Portal, { "data-slot": "dialog-portal", ...props });
|
|
1827
|
-
}
|
|
1828
|
-
function DialogOverlay({
|
|
1829
|
-
className,
|
|
1830
|
-
...props
|
|
1831
|
-
}) {
|
|
1832
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1833
|
-
radixUi.Dialog.Overlay,
|
|
1834
|
-
{
|
|
1835
|
-
"data-slot": "dialog-overlay",
|
|
1836
|
-
className: cn(
|
|
1837
|
-
"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",
|
|
1838
|
-
className
|
|
1839
|
-
),
|
|
1840
|
-
...props
|
|
1841
|
-
}
|
|
1842
|
-
);
|
|
1843
|
-
}
|
|
1844
|
-
function DialogContent({
|
|
1845
|
-
className,
|
|
1846
|
-
children,
|
|
1847
|
-
showCloseButton = true,
|
|
1848
|
-
...props
|
|
1849
|
-
}) {
|
|
1850
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
|
|
1851
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
1852
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1853
|
-
radixUi.Dialog.Content,
|
|
1854
|
-
{
|
|
1855
|
-
"data-slot": "dialog-content",
|
|
1856
|
-
className: cn(
|
|
1857
|
-
"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",
|
|
1858
|
-
className
|
|
1859
|
-
),
|
|
1860
|
-
...props,
|
|
1861
|
-
children: [
|
|
1862
|
-
children,
|
|
1863
|
-
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { "data-slot": "dialog-close", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1864
|
-
Button,
|
|
1865
|
-
{
|
|
1866
|
-
variant: "ghost",
|
|
1867
|
-
className: "absolute top-5 right-5 bg-secondary",
|
|
1868
|
-
size: "icon-sm",
|
|
1869
|
-
children: [
|
|
1870
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1871
|
-
lucideReact.XIcon,
|
|
1872
|
-
{}
|
|
1873
|
-
),
|
|
1874
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
1875
|
-
]
|
|
1876
|
-
}
|
|
1877
|
-
) })
|
|
1878
|
-
]
|
|
1879
|
-
}
|
|
1880
|
-
)
|
|
1881
|
-
] });
|
|
1882
|
-
}
|
|
1883
|
-
function DialogHeader({ className, ...props }) {
|
|
1884
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1885
|
-
"div",
|
|
1886
|
-
{
|
|
1887
|
-
"data-slot": "dialog-header",
|
|
1888
|
-
className: cn("flex flex-col gap-2", className),
|
|
1889
|
-
...props
|
|
1890
|
-
}
|
|
1891
|
-
);
|
|
1892
|
-
}
|
|
1893
|
-
function DialogFooter({
|
|
1894
|
-
className,
|
|
1895
|
-
showCloseButton = false,
|
|
1896
|
-
children,
|
|
1897
|
-
...props
|
|
1898
|
-
}) {
|
|
1899
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1900
|
-
"div",
|
|
1901
|
-
{
|
|
1902
|
-
"data-slot": "dialog-footer",
|
|
1903
|
-
className: cn(
|
|
1904
|
-
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
1905
|
-
className
|
|
1906
|
-
),
|
|
1907
|
-
...props,
|
|
1908
|
-
children: [
|
|
1909
|
-
children,
|
|
1910
|
-
showCloseButton && /* @__PURE__ */ jsxRuntime.jsx(radixUi.Dialog.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", children: "Close" }) })
|
|
1911
|
-
]
|
|
1912
|
-
}
|
|
1913
|
-
);
|
|
1914
|
-
}
|
|
1915
|
-
function DialogTitle({
|
|
1916
|
-
className,
|
|
1917
|
-
...props
|
|
1918
|
-
}) {
|
|
1919
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1920
|
-
radixUi.Dialog.Title,
|
|
1921
|
-
{
|
|
1922
|
-
"data-slot": "dialog-title",
|
|
1923
|
-
className: cn(
|
|
1924
|
-
"font-heading text-lg leading-none font-semibold tracking-wider uppercase",
|
|
1925
|
-
className
|
|
1926
|
-
),
|
|
1927
|
-
...props
|
|
1928
|
-
}
|
|
1929
|
-
);
|
|
1930
|
-
}
|
|
1931
|
-
function DialogDescription({
|
|
1932
|
-
className,
|
|
1933
|
-
...props
|
|
1934
|
-
}) {
|
|
1935
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1936
|
-
radixUi.Dialog.Description,
|
|
1937
|
-
{
|
|
1938
|
-
"data-slot": "dialog-description",
|
|
1939
|
-
className: cn(
|
|
1940
|
-
"mt-0.5 text-sm leading-relaxed text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
1941
|
-
className
|
|
1942
|
-
),
|
|
1943
|
-
...props
|
|
1944
|
-
}
|
|
1945
|
-
);
|
|
1946
|
-
}
|
|
1947
|
-
|
|
1948
|
-
// src/components/chat/tools/file-tools.tsx
|
|
1949
2196
|
init_utils();
|
|
1950
2197
|
|
|
1951
2198
|
// src/components/chat/diff-viewer.tsx
|
|
@@ -6178,6 +6425,32 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
6178
6425
|
}
|
|
6179
6426
|
return entries;
|
|
6180
6427
|
}
|
|
6428
|
+
function groupBrowserActivityEntries(entries) {
|
|
6429
|
+
const grouped = [];
|
|
6430
|
+
let buffer = [];
|
|
6431
|
+
const flush = () => {
|
|
6432
|
+
if (buffer.length === 0) return;
|
|
6433
|
+
grouped.push({
|
|
6434
|
+
kind: "browser_activity",
|
|
6435
|
+
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
6436
|
+
calls: buffer
|
|
6437
|
+
});
|
|
6438
|
+
buffer = [];
|
|
6439
|
+
};
|
|
6440
|
+
for (const entry of entries) {
|
|
6441
|
+
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
6442
|
+
buffer.push(entry.tc);
|
|
6443
|
+
continue;
|
|
6444
|
+
}
|
|
6445
|
+
flush();
|
|
6446
|
+
grouped.push(entry);
|
|
6447
|
+
}
|
|
6448
|
+
flush();
|
|
6449
|
+
return grouped;
|
|
6450
|
+
}
|
|
6451
|
+
function isBrowserToolCall(call) {
|
|
6452
|
+
return call.toolName.startsWith("browser_");
|
|
6453
|
+
}
|
|
6181
6454
|
function groupMessages(messages) {
|
|
6182
6455
|
const groups = [];
|
|
6183
6456
|
let pendingSystem = [];
|
|
@@ -6334,6 +6607,15 @@ function TimelineEntryItem({
|
|
|
6334
6607
|
] }) })
|
|
6335
6608
|
] });
|
|
6336
6609
|
}
|
|
6610
|
+
if (entry.kind === "browser_activity") {
|
|
6611
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
6612
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
6613
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
6614
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
6615
|
+
] }),
|
|
6616
|
+
/* @__PURE__ */ jsxRuntime.jsx(TimelineContent, { children: /* @__PURE__ */ jsxRuntime.jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
6617
|
+
] });
|
|
6618
|
+
}
|
|
6337
6619
|
if (entry.kind === "text") {
|
|
6338
6620
|
return /* @__PURE__ */ jsxRuntime.jsxs(TimelineItem, { step, children: [
|
|
6339
6621
|
/* @__PURE__ */ jsxRuntime.jsxs(TimelineHeader, { children: [
|
|
@@ -6395,11 +6677,12 @@ function AssistantGroup({
|
|
|
6395
6677
|
onFileSelect,
|
|
6396
6678
|
onRetry
|
|
6397
6679
|
}) {
|
|
6398
|
-
|
|
6680
|
+
let entries = [];
|
|
6399
6681
|
for (let i = 0; i < messages.length; i++) {
|
|
6400
6682
|
const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
|
|
6401
6683
|
entries.push(...messageToEntries(messages[i], isLast, artifactFallbacks));
|
|
6402
6684
|
}
|
|
6685
|
+
entries = groupBrowserActivityEntries(entries);
|
|
6403
6686
|
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
6404
6687
|
const lastEntry = entries[entries.length - 1];
|
|
6405
6688
|
const hasRunningTool = entries.some(
|
|
@@ -7476,6 +7759,7 @@ function WorkspacePanel({
|
|
|
7476
7759
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7477
7760
|
"aside",
|
|
7478
7761
|
{
|
|
7762
|
+
"data-testid": "workspace-panel",
|
|
7479
7763
|
role: "button",
|
|
7480
7764
|
tabIndex: 0,
|
|
7481
7765
|
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",
|
|
@@ -7494,6 +7778,7 @@ function WorkspacePanel({
|
|
|
7494
7778
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7495
7779
|
"aside",
|
|
7496
7780
|
{
|
|
7781
|
+
"data-testid": "workspace-panel",
|
|
7497
7782
|
className: "relative z-10 flex min-h-0 flex-col overflow-hidden border-l border-muted-foreground/20 bg-card",
|
|
7498
7783
|
style: { width, minWidth: MIN_WIDTH, maxWidth: MAX_WIDTH },
|
|
7499
7784
|
children: [
|
|
@@ -7735,6 +8020,10 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
7735
8020
|
"expert.override",
|
|
7736
8021
|
"artifact.created",
|
|
7737
8022
|
"artifact.updated",
|
|
8023
|
+
"browser.provisioned",
|
|
8024
|
+
"browser.destroyed",
|
|
8025
|
+
"browser.control_granted",
|
|
8026
|
+
"browser.control_returned",
|
|
7738
8027
|
"clarify.response"
|
|
7739
8028
|
];
|
|
7740
8029
|
|
|
@@ -7759,7 +8048,8 @@ function createInitialAgentChatState(options = {}) {
|
|
|
7759
8048
|
sessionDone: false,
|
|
7760
8049
|
hadDeltas: false,
|
|
7761
8050
|
terminal: false,
|
|
7762
|
-
workspaceRefreshKey: 0
|
|
8051
|
+
workspaceRefreshKey: 0,
|
|
8052
|
+
browser: null
|
|
7763
8053
|
};
|
|
7764
8054
|
}
|
|
7765
8055
|
function applyAgentChatEvent(state, event) {
|
|
@@ -7783,7 +8073,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7783
8073
|
{
|
|
7784
8074
|
id: `evt-${event.eventId}`,
|
|
7785
8075
|
role: "system",
|
|
7786
|
-
content:
|
|
8076
|
+
content: stringValue2(event.data.skill),
|
|
7787
8077
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7788
8078
|
status: "complete",
|
|
7789
8079
|
systemKind: "skill_invoked",
|
|
@@ -7800,7 +8090,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7800
8090
|
{
|
|
7801
8091
|
id: `evt-${event.eventId}`,
|
|
7802
8092
|
role: "system",
|
|
7803
|
-
content:
|
|
8093
|
+
content: stringValue2(event.data.name),
|
|
7804
8094
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7805
8095
|
status: "complete",
|
|
7806
8096
|
systemKind: "artifact",
|
|
@@ -7813,6 +8103,23 @@ function applyAgentChatEvent(state, event) {
|
|
|
7813
8103
|
}
|
|
7814
8104
|
}
|
|
7815
8105
|
]);
|
|
8106
|
+
case "browser.provisioned":
|
|
8107
|
+
return applyBrowserEvent(nextState, event, {
|
|
8108
|
+
status: "live",
|
|
8109
|
+
controlOwner: null
|
|
8110
|
+
});
|
|
8111
|
+
case "browser.control_granted":
|
|
8112
|
+
return applyBrowserEvent(nextState, event, {
|
|
8113
|
+
status: "user-control",
|
|
8114
|
+
controlOwner: stringValue2(event.data.owner_user_id) || null
|
|
8115
|
+
});
|
|
8116
|
+
case "browser.control_returned":
|
|
8117
|
+
return applyBrowserEvent(nextState, event, {
|
|
8118
|
+
status: "live",
|
|
8119
|
+
controlOwner: null
|
|
8120
|
+
});
|
|
8121
|
+
case "browser.destroyed":
|
|
8122
|
+
return applyBrowserEvent(nextState, event, null);
|
|
7816
8123
|
case "llm.delta":
|
|
7817
8124
|
return applyLlmDelta(nextState, event);
|
|
7818
8125
|
case "llm.response":
|
|
@@ -7822,7 +8129,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7822
8129
|
case "tool.call":
|
|
7823
8130
|
return applyToolCall(nextState, event);
|
|
7824
8131
|
case "tool.result": {
|
|
7825
|
-
const toolCallId =
|
|
8132
|
+
const toolCallId = stringValue2(event.data.tool_call_id);
|
|
7826
8133
|
const toolName = findToolNameById(nextState.messages, toolCallId);
|
|
7827
8134
|
const messages = applyToolResult(nextState.messages, event.data);
|
|
7828
8135
|
const mutatesWorkspace = toolName !== null && WORKSPACE_MUTATING_TOOLS.has(toolName);
|
|
@@ -7892,8 +8199,8 @@ function applyRetryIndicator(state, event) {
|
|
|
7892
8199
|
case "session.done":
|
|
7893
8200
|
return { ...state, retryIndicator: null };
|
|
7894
8201
|
case "harness.crash": {
|
|
7895
|
-
const title =
|
|
7896
|
-
const detail =
|
|
8202
|
+
const title = stringValue2(event.data.error_title) || "A transient error occurred, retrying...";
|
|
8203
|
+
const detail = stringValue2(event.data.error_detail) || stringValue2(event.data.error);
|
|
7897
8204
|
return {
|
|
7898
8205
|
...state,
|
|
7899
8206
|
retryIndicator: {
|
|
@@ -7908,7 +8215,7 @@ function applyRetryIndicator(state, event) {
|
|
|
7908
8215
|
}
|
|
7909
8216
|
}
|
|
7910
8217
|
function applyUserMessage(messages, eventId, data) {
|
|
7911
|
-
const content =
|
|
8218
|
+
const content = stringValue2(data.content);
|
|
7912
8219
|
const next = [...messages];
|
|
7913
8220
|
const localIdx = next.findIndex(
|
|
7914
8221
|
(m) => m.role === "user" && m.id.startsWith("local-") && m.content === content
|
|
@@ -7926,9 +8233,47 @@ function applyUserMessage(messages, eventId, data) {
|
|
|
7926
8233
|
});
|
|
7927
8234
|
return next;
|
|
7928
8235
|
}
|
|
8236
|
+
function applyBrowserEvent(state, event, browser) {
|
|
8237
|
+
return withMessages(
|
|
8238
|
+
{ ...state, browser },
|
|
8239
|
+
[...state.messages, browserMarker(event)]
|
|
8240
|
+
);
|
|
8241
|
+
}
|
|
8242
|
+
function browserMarker(event) {
|
|
8243
|
+
const labels = {
|
|
8244
|
+
"browser.provisioned": {
|
|
8245
|
+
content: "Browser ready.",
|
|
8246
|
+
warning: false
|
|
8247
|
+
},
|
|
8248
|
+
"browser.control_granted": {
|
|
8249
|
+
content: "A user took control of the browser.",
|
|
8250
|
+
warning: true
|
|
8251
|
+
},
|
|
8252
|
+
"browser.control_returned": {
|
|
8253
|
+
content: "Browser control returned to the agent.",
|
|
8254
|
+
warning: false
|
|
8255
|
+
},
|
|
8256
|
+
"browser.destroyed": {
|
|
8257
|
+
content: "Browser closed.",
|
|
8258
|
+
warning: false
|
|
8259
|
+
}
|
|
8260
|
+
};
|
|
8261
|
+
const label = labels[event.type] ?? {
|
|
8262
|
+
content: "Browser updated.",
|
|
8263
|
+
warning: false
|
|
8264
|
+
};
|
|
8265
|
+
return {
|
|
8266
|
+
id: `browser-marker-${event.eventId}`,
|
|
8267
|
+
role: "system",
|
|
8268
|
+
content: label.content,
|
|
8269
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
8270
|
+
status: "complete",
|
|
8271
|
+
systemKind: label.warning ? "browser_marker_warning" : "browser_marker"
|
|
8272
|
+
};
|
|
8273
|
+
}
|
|
7929
8274
|
function applyLlmDelta(state, event) {
|
|
7930
|
-
const deltaContent =
|
|
7931
|
-
const deltaReasoning =
|
|
8275
|
+
const deltaContent = stringValue2(event.data.content);
|
|
8276
|
+
const deltaReasoning = stringValue2(event.data.reasoning);
|
|
7932
8277
|
const messages = [...state.messages];
|
|
7933
8278
|
const lastIdx = findLastAssistantIndex(messages);
|
|
7934
8279
|
const lastMsg = lastIdx >= 0 ? messages[lastIdx] : null;
|
|
@@ -7965,7 +8310,7 @@ function applyLlmDelta(state, event) {
|
|
|
7965
8310
|
function applyLlmResponse(state, event) {
|
|
7966
8311
|
const messages = [...state.messages];
|
|
7967
8312
|
const message = objectValue(event.data.message);
|
|
7968
|
-
const responseContent =
|
|
8313
|
+
const responseContent = stringValue2(message?.content) || stringValue2(event.data.content);
|
|
7969
8314
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
7970
8315
|
const hasToolCalls = toolCalls.length > 0;
|
|
7971
8316
|
const idx = findLastAssistantIndex(messages);
|
|
@@ -8023,12 +8368,12 @@ function applyLlmResponse(state, event) {
|
|
|
8023
8368
|
cachedInputTokens: numberValue(event.data.cache_read_tokens),
|
|
8024
8369
|
totalTokens: inputTokens + outputTokens,
|
|
8025
8370
|
contextWindow: numberValue(event.data.context_window),
|
|
8026
|
-
model:
|
|
8371
|
+
model: stringValue2(event.data.model)
|
|
8027
8372
|
}
|
|
8028
8373
|
};
|
|
8029
8374
|
}
|
|
8030
8375
|
function applyLlmThinking(state, event) {
|
|
8031
|
-
const reasoningText =
|
|
8376
|
+
const reasoningText = stringValue2(event.data.reasoning) || stringValue2(event.data.content);
|
|
8032
8377
|
const messages = [...state.messages];
|
|
8033
8378
|
const idx = findLastAssistantIndex(messages);
|
|
8034
8379
|
const prev = idx >= 0 ? messages[idx] : null;
|
|
@@ -8076,11 +8421,11 @@ function applyToolCall(state, event) {
|
|
|
8076
8421
|
messages[assistantIdx] = assistant;
|
|
8077
8422
|
}
|
|
8078
8423
|
const existingCalls = assistant.toolCalls ?? [];
|
|
8079
|
-
const toolCallId =
|
|
8424
|
+
const toolCallId = stringValue2(event.data.tool_call_id) || `tc-${event.eventId}`;
|
|
8080
8425
|
if (!existingCalls.some((tc) => tc.id === toolCallId)) {
|
|
8081
8426
|
const entry = {
|
|
8082
8427
|
id: toolCallId,
|
|
8083
|
-
toolName:
|
|
8428
|
+
toolName: stringValue2(event.data.name) || stringValue2(event.data.tool_name) || "unknown",
|
|
8084
8429
|
args: typeof event.data.arguments === "string" ? event.data.arguments : JSON.stringify(event.data.arguments ?? {}),
|
|
8085
8430
|
status: "running"
|
|
8086
8431
|
};
|
|
@@ -8096,7 +8441,7 @@ function applyToolCall(state, event) {
|
|
|
8096
8441
|
};
|
|
8097
8442
|
}
|
|
8098
8443
|
function applyToolResult(messages, data) {
|
|
8099
|
-
const targetId =
|
|
8444
|
+
const targetId = stringValue2(data.tool_call_id);
|
|
8100
8445
|
let matchIdx = -1;
|
|
8101
8446
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
8102
8447
|
if (messages[i]?.role === "assistant" && messages[i]?.toolCalls?.some((tc) => tc.id === targetId)) {
|
|
@@ -8165,8 +8510,8 @@ function buildErrorInfo(event) {
|
|
|
8165
8510
|
}
|
|
8166
8511
|
return {
|
|
8167
8512
|
category: event.data.error_category,
|
|
8168
|
-
title:
|
|
8169
|
-
detail:
|
|
8513
|
+
title: stringValue2(event.data.error_title) || "The session failed due to an internal error.",
|
|
8514
|
+
detail: stringValue2(event.data.error_detail) || stringValue2(event.data.error),
|
|
8170
8515
|
retryable: Boolean(event.data.retryable)
|
|
8171
8516
|
};
|
|
8172
8517
|
}
|
|
@@ -8210,7 +8555,7 @@ function applyExpertFeedback(messages, type, data) {
|
|
|
8210
8555
|
return messages;
|
|
8211
8556
|
}
|
|
8212
8557
|
function applyClarifyResponse(messages, data) {
|
|
8213
|
-
const targetToolId =
|
|
8558
|
+
const targetToolId = stringValue2(data.tool_call_id);
|
|
8214
8559
|
const responses = Array.isArray(data.responses) ? data.responses : void 0;
|
|
8215
8560
|
if (!targetToolId || !responses) return messages;
|
|
8216
8561
|
const next = [...messages];
|
|
@@ -8225,8 +8570,8 @@ function applyClarifyResponse(messages, data) {
|
|
|
8225
8570
|
clarifyAnswers: responses.map((response) => {
|
|
8226
8571
|
const row = objectValue(response) ?? {};
|
|
8227
8572
|
return {
|
|
8228
|
-
question:
|
|
8229
|
-
answer:
|
|
8573
|
+
question: stringValue2(row.question),
|
|
8574
|
+
answer: stringValue2(row.answer),
|
|
8230
8575
|
is_other: Boolean(row.is_other)
|
|
8231
8576
|
};
|
|
8232
8577
|
})
|
|
@@ -8246,7 +8591,7 @@ function applyPolicyDenied(state, data) {
|
|
|
8246
8591
|
...policyMsg,
|
|
8247
8592
|
content: `${policyMsg.content}
|
|
8248
8593
|
|
|
8249
|
-
**Policy denied**: ${
|
|
8594
|
+
**Policy denied**: ${stringValue2(data.reason) || "Action blocked by governance policy."}`,
|
|
8250
8595
|
status: "error"
|
|
8251
8596
|
};
|
|
8252
8597
|
}
|
|
@@ -8298,7 +8643,7 @@ function objectValue(value) {
|
|
|
8298
8643
|
}
|
|
8299
8644
|
return void 0;
|
|
8300
8645
|
}
|
|
8301
|
-
function
|
|
8646
|
+
function stringValue2(value) {
|
|
8302
8647
|
return typeof value === "string" ? value : "";
|
|
8303
8648
|
}
|
|
8304
8649
|
function numberValue(value) {
|
|
@@ -8532,6 +8877,7 @@ function useAgentChatRuntime({
|
|
|
8532
8877
|
}
|
|
8533
8878
|
}, [adapter, sessionId]);
|
|
8534
8879
|
return {
|
|
8880
|
+
state,
|
|
8535
8881
|
session,
|
|
8536
8882
|
messages: state.messages,
|
|
8537
8883
|
isRunning: state.isRunning,
|
|
@@ -8583,6 +8929,7 @@ function AgentChat({
|
|
|
8583
8929
|
const isReadOnlySession = isScheduledRunSession(runtime.session);
|
|
8584
8930
|
const effectiveDisabled = disabled || isReadOnlySession;
|
|
8585
8931
|
const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
|
|
8932
|
+
const browserState = runtime.state.browser;
|
|
8586
8933
|
react.useEffect(() => {
|
|
8587
8934
|
onMessagesChange?.(runtime.messages);
|
|
8588
8935
|
}, [onMessagesChange, runtime.messages]);
|
|
@@ -8619,19 +8966,29 @@ function AgentChat({
|
|
|
8619
8966
|
retryIndicator: runtime.retryIndicator
|
|
8620
8967
|
}
|
|
8621
8968
|
) }),
|
|
8622
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
|
|
8969
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-testid": "right-stack", className: "flex min-h-0 shrink-0 flex-col", children: [
|
|
8970
|
+
browserState !== null && sessionId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 border-b border-line", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8971
|
+
BrowserPane,
|
|
8972
|
+
{
|
|
8973
|
+
sessionId,
|
|
8974
|
+
state: browserState,
|
|
8975
|
+
adapter
|
|
8976
|
+
}
|
|
8977
|
+
) }),
|
|
8978
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8979
|
+
WorkspacePanel,
|
|
8980
|
+
{
|
|
8981
|
+
adapter,
|
|
8982
|
+
sessionId,
|
|
8983
|
+
selectedPath: workspacePath,
|
|
8984
|
+
onSelectedPathChange: setWorkspacePath,
|
|
8985
|
+
collapsed: workspaceCollapsed,
|
|
8986
|
+
onCollapsedChange: setWorkspaceCollapsed,
|
|
8987
|
+
refreshSignal: runtime.workspaceRefreshKey,
|
|
8988
|
+
disabled: effectiveDisabled
|
|
8989
|
+
}
|
|
8990
|
+
)
|
|
8991
|
+
] })
|
|
8635
8992
|
] }) })
|
|
8636
8993
|
}
|
|
8637
8994
|
);
|