@invergent/agent-chat-react 1.5.10 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +332 -37
- 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 +329 -37
- 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, FolderOpenIcon, UploadIcon, RefreshCwIcon, AlertCircleIcon, SquareIcon, ArrowDownIcon, RotateCcwIcon, MousePointer2Icon, DownloadIcon, TrashIcon, ImageIcon, FileTextIcon, Maximize2Icon, 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,114 @@ 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({ src }) {
|
|
128
|
+
return /* @__PURE__ */ jsx(
|
|
129
|
+
"iframe",
|
|
130
|
+
{
|
|
131
|
+
"data-testid": "browser-iframe",
|
|
132
|
+
title: "Browser live view",
|
|
133
|
+
src,
|
|
134
|
+
className: "h-full w-full border-0 bg-black",
|
|
135
|
+
allow: "clipboard-read; clipboard-write"
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
function BrowserStatusDot({
|
|
140
|
+
status
|
|
141
|
+
}) {
|
|
142
|
+
return /* @__PURE__ */ jsx(
|
|
143
|
+
"span",
|
|
144
|
+
{
|
|
145
|
+
"aria-hidden": "true",
|
|
146
|
+
className: cn(
|
|
147
|
+
"inline-block size-2 shrink-0 rounded-full",
|
|
148
|
+
status === "live" && "bg-emerald-500",
|
|
149
|
+
status === "user-control" && "bg-amber-500",
|
|
150
|
+
status === "provisioning" && "animate-pulse bg-sky-500",
|
|
151
|
+
status === "closed" && "bg-muted-foreground"
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
function BrowserPane({ sessionId, state, adapter }) {
|
|
157
|
+
const liveViewUrl = useMemo(
|
|
158
|
+
() => adapter.browserLiveViewUrl(sessionId),
|
|
159
|
+
[adapter, sessionId]
|
|
160
|
+
);
|
|
161
|
+
const hasLiveView = state.status !== "provisioning" && state.status !== "closed";
|
|
162
|
+
return /* @__PURE__ */ jsxs(
|
|
163
|
+
"div",
|
|
164
|
+
{
|
|
165
|
+
"data-testid": "browser-pane",
|
|
166
|
+
className: "flex h-full min-h-0 flex-col bg-background",
|
|
167
|
+
children: [
|
|
168
|
+
/* @__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: [
|
|
169
|
+
/* @__PURE__ */ jsx(ZapIcon, { className: "size-3.5 text-muted-foreground", "aria-hidden": "true" }),
|
|
170
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: "Browser" }),
|
|
171
|
+
/* @__PURE__ */ jsx(BrowserStatusDot, { status: state.status }),
|
|
172
|
+
state.controlOwner && /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-amber-500", children: [
|
|
173
|
+
state.controlOwner,
|
|
174
|
+
" has control"
|
|
175
|
+
] })
|
|
176
|
+
] }),
|
|
177
|
+
/* @__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." }) : /* @__PURE__ */ jsx(BrowserLiveView, { src: liveViewUrl }) }),
|
|
178
|
+
hasLiveView && /* @__PURE__ */ jsx(
|
|
179
|
+
BrowserControlBar,
|
|
180
|
+
{
|
|
181
|
+
sessionId,
|
|
182
|
+
hasControl: state.status === "user-control",
|
|
183
|
+
adapter
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
}
|
|
82
190
|
var Conversation = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
83
191
|
StickToBottom,
|
|
84
192
|
{
|
|
@@ -565,6 +673,80 @@ function TimelineSeparator({
|
|
|
565
673
|
}
|
|
566
674
|
);
|
|
567
675
|
}
|
|
676
|
+
function BrowserActivityGroup({ calls }) {
|
|
677
|
+
const [open, setOpen] = useState(false);
|
|
678
|
+
const latest = calls[calls.length - 1];
|
|
679
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-none border border-line bg-card text-xs", children: [
|
|
680
|
+
/* @__PURE__ */ jsxs(
|
|
681
|
+
"button",
|
|
682
|
+
{
|
|
683
|
+
type: "button",
|
|
684
|
+
onClick: () => setOpen((current) => !current),
|
|
685
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-muted/40",
|
|
686
|
+
children: [
|
|
687
|
+
open ? /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3 shrink-0", "aria-hidden": "true" }),
|
|
688
|
+
/* @__PURE__ */ jsx(ZapIcon, { className: "size-3 shrink-0 text-amber-500", "aria-hidden": "true" }),
|
|
689
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "browser" }),
|
|
690
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-muted-foreground", children: [
|
|
691
|
+
"(",
|
|
692
|
+
calls.length,
|
|
693
|
+
" ",
|
|
694
|
+
calls.length === 1 ? "action" : "actions",
|
|
695
|
+
" - latest:",
|
|
696
|
+
" ",
|
|
697
|
+
latest ? summarise(latest) : "none",
|
|
698
|
+
")"
|
|
699
|
+
] })
|
|
700
|
+
]
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
open && /* @__PURE__ */ jsx("ul", { className: "border-t border-line py-1", children: calls.map((call) => {
|
|
704
|
+
const error = stringValue(parseJson(call.result).error);
|
|
705
|
+
return /* @__PURE__ */ jsxs(
|
|
706
|
+
"li",
|
|
707
|
+
{
|
|
708
|
+
className: "flex items-center gap-2 px-6 py-1 font-mono text-[11px]",
|
|
709
|
+
children: [
|
|
710
|
+
error && /* @__PURE__ */ jsx(
|
|
711
|
+
AlertCircleIcon,
|
|
712
|
+
{
|
|
713
|
+
"data-testid": `activity-error-${call.id}`,
|
|
714
|
+
className: "size-3 shrink-0 text-destructive",
|
|
715
|
+
"aria-hidden": "true"
|
|
716
|
+
}
|
|
717
|
+
),
|
|
718
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: summarise(call) }),
|
|
719
|
+
error && /* @__PURE__ */ jsx("span", { className: "ml-auto max-w-40 truncate text-destructive", children: error })
|
|
720
|
+
]
|
|
721
|
+
},
|
|
722
|
+
call.id
|
|
723
|
+
);
|
|
724
|
+
}) })
|
|
725
|
+
] });
|
|
726
|
+
}
|
|
727
|
+
function summarise(call) {
|
|
728
|
+
const verb = call.toolName.replace(/^browser_/, "");
|
|
729
|
+
const args = parseJson(call.args);
|
|
730
|
+
const ref = stringValue(args.ref);
|
|
731
|
+
const url = stringValue(args.url);
|
|
732
|
+
const text = stringValue(args.text);
|
|
733
|
+
if (url) return `${verb} ${url}`;
|
|
734
|
+
if (ref) return `${verb} ${ref}`;
|
|
735
|
+
if (text) return `${verb} "${text.slice(0, 24)}"`;
|
|
736
|
+
return verb;
|
|
737
|
+
}
|
|
738
|
+
function parseJson(raw) {
|
|
739
|
+
if (!raw) return {};
|
|
740
|
+
try {
|
|
741
|
+
const parsed = JSON.parse(raw);
|
|
742
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
|
|
743
|
+
} catch {
|
|
744
|
+
return {};
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
function stringValue(value) {
|
|
748
|
+
return typeof value === "string" ? value : "";
|
|
749
|
+
}
|
|
568
750
|
|
|
569
751
|
// src/components/chat/tools/shared.ts
|
|
570
752
|
function statusColorClass(status) {
|
|
@@ -5886,6 +6068,32 @@ function messageToEntries(msg, isLast, artifactFallbacks) {
|
|
|
5886
6068
|
}
|
|
5887
6069
|
return entries;
|
|
5888
6070
|
}
|
|
6071
|
+
function groupBrowserActivityEntries(entries) {
|
|
6072
|
+
const grouped = [];
|
|
6073
|
+
let buffer = [];
|
|
6074
|
+
const flush = () => {
|
|
6075
|
+
if (buffer.length === 0) return;
|
|
6076
|
+
grouped.push({
|
|
6077
|
+
kind: "browser_activity",
|
|
6078
|
+
key: `browser-activity-${buffer[0]?.id}-${buffer[buffer.length - 1]?.id}`,
|
|
6079
|
+
calls: buffer
|
|
6080
|
+
});
|
|
6081
|
+
buffer = [];
|
|
6082
|
+
};
|
|
6083
|
+
for (const entry of entries) {
|
|
6084
|
+
if (entry.kind === "tool" && isBrowserToolCall(entry.tc)) {
|
|
6085
|
+
buffer.push(entry.tc);
|
|
6086
|
+
continue;
|
|
6087
|
+
}
|
|
6088
|
+
flush();
|
|
6089
|
+
grouped.push(entry);
|
|
6090
|
+
}
|
|
6091
|
+
flush();
|
|
6092
|
+
return grouped;
|
|
6093
|
+
}
|
|
6094
|
+
function isBrowserToolCall(call) {
|
|
6095
|
+
return call.toolName.startsWith("browser_");
|
|
6096
|
+
}
|
|
5889
6097
|
function groupMessages(messages) {
|
|
5890
6098
|
const groups = [];
|
|
5891
6099
|
let pendingSystem = [];
|
|
@@ -6042,6 +6250,15 @@ function TimelineEntryItem({
|
|
|
6042
6250
|
] }) })
|
|
6043
6251
|
] });
|
|
6044
6252
|
}
|
|
6253
|
+
if (entry.kind === "browser_activity") {
|
|
6254
|
+
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
6255
|
+
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
6256
|
+
/* @__PURE__ */ jsx(TimelineSeparator, { style: { backgroundColor: "var(--color-border)" } }),
|
|
6257
|
+
/* @__PURE__ */ jsx(TimelineIndicator, { className: "size-2 border-none bg-amber-500" })
|
|
6258
|
+
] }),
|
|
6259
|
+
/* @__PURE__ */ jsx(TimelineContent, { children: /* @__PURE__ */ jsx(BrowserActivityGroup, { calls: entry.calls }) })
|
|
6260
|
+
] });
|
|
6261
|
+
}
|
|
6045
6262
|
if (entry.kind === "text") {
|
|
6046
6263
|
return /* @__PURE__ */ jsxs(TimelineItem, { step, children: [
|
|
6047
6264
|
/* @__PURE__ */ jsxs(TimelineHeader, { children: [
|
|
@@ -6103,11 +6320,12 @@ function AssistantGroup({
|
|
|
6103
6320
|
onFileSelect,
|
|
6104
6321
|
onRetry
|
|
6105
6322
|
}) {
|
|
6106
|
-
|
|
6323
|
+
let entries = [];
|
|
6107
6324
|
for (let i = 0; i < messages.length; i++) {
|
|
6108
6325
|
const isLast = i === messages.length - 1 && lastGlobalIndex === totalMessages - 1;
|
|
6109
6326
|
entries.push(...messageToEntries(messages[i], isLast, artifactFallbacks));
|
|
6110
6327
|
}
|
|
6328
|
+
entries = groupBrowserActivityEntries(entries);
|
|
6111
6329
|
const isTailGroup = lastGlobalIndex === totalMessages - 1;
|
|
6112
6330
|
const lastEntry = entries[entries.length - 1];
|
|
6113
6331
|
const hasRunningTool = entries.some(
|
|
@@ -7175,6 +7393,7 @@ function WorkspacePanel({
|
|
|
7175
7393
|
return /* @__PURE__ */ jsx(
|
|
7176
7394
|
"aside",
|
|
7177
7395
|
{
|
|
7396
|
+
"data-testid": "workspace-panel",
|
|
7178
7397
|
role: "button",
|
|
7179
7398
|
tabIndex: 0,
|
|
7180
7399
|
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 +7412,7 @@ function WorkspacePanel({
|
|
|
7193
7412
|
return /* @__PURE__ */ jsxs(
|
|
7194
7413
|
"aside",
|
|
7195
7414
|
{
|
|
7415
|
+
"data-testid": "workspace-panel",
|
|
7196
7416
|
className: "relative z-10 flex min-h-0 flex-col overflow-hidden border-l border-muted-foreground/20 bg-card",
|
|
7197
7417
|
style: { width, minWidth: MIN_WIDTH, maxWidth: MAX_WIDTH },
|
|
7198
7418
|
children: [
|
|
@@ -7434,6 +7654,10 @@ var AGENT_CHAT_LISTENED_EVENTS = [
|
|
|
7434
7654
|
"expert.override",
|
|
7435
7655
|
"artifact.created",
|
|
7436
7656
|
"artifact.updated",
|
|
7657
|
+
"browser.provisioned",
|
|
7658
|
+
"browser.destroyed",
|
|
7659
|
+
"browser.control_granted",
|
|
7660
|
+
"browser.control_returned",
|
|
7437
7661
|
"clarify.response"
|
|
7438
7662
|
];
|
|
7439
7663
|
|
|
@@ -7458,7 +7682,8 @@ function createInitialAgentChatState(options = {}) {
|
|
|
7458
7682
|
sessionDone: false,
|
|
7459
7683
|
hadDeltas: false,
|
|
7460
7684
|
terminal: false,
|
|
7461
|
-
workspaceRefreshKey: 0
|
|
7685
|
+
workspaceRefreshKey: 0,
|
|
7686
|
+
browser: null
|
|
7462
7687
|
};
|
|
7463
7688
|
}
|
|
7464
7689
|
function applyAgentChatEvent(state, event) {
|
|
@@ -7482,7 +7707,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7482
7707
|
{
|
|
7483
7708
|
id: `evt-${event.eventId}`,
|
|
7484
7709
|
role: "system",
|
|
7485
|
-
content:
|
|
7710
|
+
content: stringValue2(event.data.skill),
|
|
7486
7711
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7487
7712
|
status: "complete",
|
|
7488
7713
|
systemKind: "skill_invoked",
|
|
@@ -7499,7 +7724,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7499
7724
|
{
|
|
7500
7725
|
id: `evt-${event.eventId}`,
|
|
7501
7726
|
role: "system",
|
|
7502
|
-
content:
|
|
7727
|
+
content: stringValue2(event.data.name),
|
|
7503
7728
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7504
7729
|
status: "complete",
|
|
7505
7730
|
systemKind: "artifact",
|
|
@@ -7512,6 +7737,23 @@ function applyAgentChatEvent(state, event) {
|
|
|
7512
7737
|
}
|
|
7513
7738
|
}
|
|
7514
7739
|
]);
|
|
7740
|
+
case "browser.provisioned":
|
|
7741
|
+
return applyBrowserEvent(nextState, event, {
|
|
7742
|
+
status: "live",
|
|
7743
|
+
controlOwner: null
|
|
7744
|
+
});
|
|
7745
|
+
case "browser.control_granted":
|
|
7746
|
+
return applyBrowserEvent(nextState, event, {
|
|
7747
|
+
status: "user-control",
|
|
7748
|
+
controlOwner: stringValue2(event.data.owner_user_id) || null
|
|
7749
|
+
});
|
|
7750
|
+
case "browser.control_returned":
|
|
7751
|
+
return applyBrowserEvent(nextState, event, {
|
|
7752
|
+
status: "live",
|
|
7753
|
+
controlOwner: null
|
|
7754
|
+
});
|
|
7755
|
+
case "browser.destroyed":
|
|
7756
|
+
return applyBrowserEvent(nextState, event, null);
|
|
7515
7757
|
case "llm.delta":
|
|
7516
7758
|
return applyLlmDelta(nextState, event);
|
|
7517
7759
|
case "llm.response":
|
|
@@ -7521,7 +7763,7 @@ function applyAgentChatEvent(state, event) {
|
|
|
7521
7763
|
case "tool.call":
|
|
7522
7764
|
return applyToolCall(nextState, event);
|
|
7523
7765
|
case "tool.result": {
|
|
7524
|
-
const toolCallId =
|
|
7766
|
+
const toolCallId = stringValue2(event.data.tool_call_id);
|
|
7525
7767
|
const toolName = findToolNameById(nextState.messages, toolCallId);
|
|
7526
7768
|
const messages = applyToolResult(nextState.messages, event.data);
|
|
7527
7769
|
const mutatesWorkspace = toolName !== null && WORKSPACE_MUTATING_TOOLS.has(toolName);
|
|
@@ -7591,8 +7833,8 @@ function applyRetryIndicator(state, event) {
|
|
|
7591
7833
|
case "session.done":
|
|
7592
7834
|
return { ...state, retryIndicator: null };
|
|
7593
7835
|
case "harness.crash": {
|
|
7594
|
-
const title =
|
|
7595
|
-
const detail =
|
|
7836
|
+
const title = stringValue2(event.data.error_title) || "A transient error occurred, retrying...";
|
|
7837
|
+
const detail = stringValue2(event.data.error_detail) || stringValue2(event.data.error);
|
|
7596
7838
|
return {
|
|
7597
7839
|
...state,
|
|
7598
7840
|
retryIndicator: {
|
|
@@ -7607,7 +7849,7 @@ function applyRetryIndicator(state, event) {
|
|
|
7607
7849
|
}
|
|
7608
7850
|
}
|
|
7609
7851
|
function applyUserMessage(messages, eventId, data) {
|
|
7610
|
-
const content =
|
|
7852
|
+
const content = stringValue2(data.content);
|
|
7611
7853
|
const next = [...messages];
|
|
7612
7854
|
const localIdx = next.findIndex(
|
|
7613
7855
|
(m) => m.role === "user" && m.id.startsWith("local-") && m.content === content
|
|
@@ -7625,9 +7867,47 @@ function applyUserMessage(messages, eventId, data) {
|
|
|
7625
7867
|
});
|
|
7626
7868
|
return next;
|
|
7627
7869
|
}
|
|
7870
|
+
function applyBrowserEvent(state, event, browser) {
|
|
7871
|
+
return withMessages(
|
|
7872
|
+
{ ...state, browser },
|
|
7873
|
+
[...state.messages, browserMarker(event)]
|
|
7874
|
+
);
|
|
7875
|
+
}
|
|
7876
|
+
function browserMarker(event) {
|
|
7877
|
+
const labels = {
|
|
7878
|
+
"browser.provisioned": {
|
|
7879
|
+
content: "Browser ready.",
|
|
7880
|
+
warning: false
|
|
7881
|
+
},
|
|
7882
|
+
"browser.control_granted": {
|
|
7883
|
+
content: "A user took control of the browser.",
|
|
7884
|
+
warning: true
|
|
7885
|
+
},
|
|
7886
|
+
"browser.control_returned": {
|
|
7887
|
+
content: "Browser control returned to the agent.",
|
|
7888
|
+
warning: false
|
|
7889
|
+
},
|
|
7890
|
+
"browser.destroyed": {
|
|
7891
|
+
content: "Browser closed.",
|
|
7892
|
+
warning: false
|
|
7893
|
+
}
|
|
7894
|
+
};
|
|
7895
|
+
const label = labels[event.type] ?? {
|
|
7896
|
+
content: "Browser updated.",
|
|
7897
|
+
warning: false
|
|
7898
|
+
};
|
|
7899
|
+
return {
|
|
7900
|
+
id: `browser-marker-${event.eventId}`,
|
|
7901
|
+
role: "system",
|
|
7902
|
+
content: label.content,
|
|
7903
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
7904
|
+
status: "complete",
|
|
7905
|
+
systemKind: label.warning ? "browser_marker_warning" : "browser_marker"
|
|
7906
|
+
};
|
|
7907
|
+
}
|
|
7628
7908
|
function applyLlmDelta(state, event) {
|
|
7629
|
-
const deltaContent =
|
|
7630
|
-
const deltaReasoning =
|
|
7909
|
+
const deltaContent = stringValue2(event.data.content);
|
|
7910
|
+
const deltaReasoning = stringValue2(event.data.reasoning);
|
|
7631
7911
|
const messages = [...state.messages];
|
|
7632
7912
|
const lastIdx = findLastAssistantIndex(messages);
|
|
7633
7913
|
const lastMsg = lastIdx >= 0 ? messages[lastIdx] : null;
|
|
@@ -7664,7 +7944,7 @@ function applyLlmDelta(state, event) {
|
|
|
7664
7944
|
function applyLlmResponse(state, event) {
|
|
7665
7945
|
const messages = [...state.messages];
|
|
7666
7946
|
const message = objectValue(event.data.message);
|
|
7667
|
-
const responseContent =
|
|
7947
|
+
const responseContent = stringValue2(message?.content) || stringValue2(event.data.content);
|
|
7668
7948
|
const toolCalls = Array.isArray(message?.tool_calls) ? message?.tool_calls : [];
|
|
7669
7949
|
const hasToolCalls = toolCalls.length > 0;
|
|
7670
7950
|
const idx = findLastAssistantIndex(messages);
|
|
@@ -7722,12 +8002,12 @@ function applyLlmResponse(state, event) {
|
|
|
7722
8002
|
cachedInputTokens: numberValue(event.data.cache_read_tokens),
|
|
7723
8003
|
totalTokens: inputTokens + outputTokens,
|
|
7724
8004
|
contextWindow: numberValue(event.data.context_window),
|
|
7725
|
-
model:
|
|
8005
|
+
model: stringValue2(event.data.model)
|
|
7726
8006
|
}
|
|
7727
8007
|
};
|
|
7728
8008
|
}
|
|
7729
8009
|
function applyLlmThinking(state, event) {
|
|
7730
|
-
const reasoningText =
|
|
8010
|
+
const reasoningText = stringValue2(event.data.reasoning) || stringValue2(event.data.content);
|
|
7731
8011
|
const messages = [...state.messages];
|
|
7732
8012
|
const idx = findLastAssistantIndex(messages);
|
|
7733
8013
|
const prev = idx >= 0 ? messages[idx] : null;
|
|
@@ -7775,11 +8055,11 @@ function applyToolCall(state, event) {
|
|
|
7775
8055
|
messages[assistantIdx] = assistant;
|
|
7776
8056
|
}
|
|
7777
8057
|
const existingCalls = assistant.toolCalls ?? [];
|
|
7778
|
-
const toolCallId =
|
|
8058
|
+
const toolCallId = stringValue2(event.data.tool_call_id) || `tc-${event.eventId}`;
|
|
7779
8059
|
if (!existingCalls.some((tc) => tc.id === toolCallId)) {
|
|
7780
8060
|
const entry = {
|
|
7781
8061
|
id: toolCallId,
|
|
7782
|
-
toolName:
|
|
8062
|
+
toolName: stringValue2(event.data.name) || stringValue2(event.data.tool_name) || "unknown",
|
|
7783
8063
|
args: typeof event.data.arguments === "string" ? event.data.arguments : JSON.stringify(event.data.arguments ?? {}),
|
|
7784
8064
|
status: "running"
|
|
7785
8065
|
};
|
|
@@ -7795,7 +8075,7 @@ function applyToolCall(state, event) {
|
|
|
7795
8075
|
};
|
|
7796
8076
|
}
|
|
7797
8077
|
function applyToolResult(messages, data) {
|
|
7798
|
-
const targetId =
|
|
8078
|
+
const targetId = stringValue2(data.tool_call_id);
|
|
7799
8079
|
let matchIdx = -1;
|
|
7800
8080
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
7801
8081
|
if (messages[i]?.role === "assistant" && messages[i]?.toolCalls?.some((tc) => tc.id === targetId)) {
|
|
@@ -7864,8 +8144,8 @@ function buildErrorInfo(event) {
|
|
|
7864
8144
|
}
|
|
7865
8145
|
return {
|
|
7866
8146
|
category: event.data.error_category,
|
|
7867
|
-
title:
|
|
7868
|
-
detail:
|
|
8147
|
+
title: stringValue2(event.data.error_title) || "The session failed due to an internal error.",
|
|
8148
|
+
detail: stringValue2(event.data.error_detail) || stringValue2(event.data.error),
|
|
7869
8149
|
retryable: Boolean(event.data.retryable)
|
|
7870
8150
|
};
|
|
7871
8151
|
}
|
|
@@ -7909,7 +8189,7 @@ function applyExpertFeedback(messages, type, data) {
|
|
|
7909
8189
|
return messages;
|
|
7910
8190
|
}
|
|
7911
8191
|
function applyClarifyResponse(messages, data) {
|
|
7912
|
-
const targetToolId =
|
|
8192
|
+
const targetToolId = stringValue2(data.tool_call_id);
|
|
7913
8193
|
const responses = Array.isArray(data.responses) ? data.responses : void 0;
|
|
7914
8194
|
if (!targetToolId || !responses) return messages;
|
|
7915
8195
|
const next = [...messages];
|
|
@@ -7924,8 +8204,8 @@ function applyClarifyResponse(messages, data) {
|
|
|
7924
8204
|
clarifyAnswers: responses.map((response) => {
|
|
7925
8205
|
const row = objectValue(response) ?? {};
|
|
7926
8206
|
return {
|
|
7927
|
-
question:
|
|
7928
|
-
answer:
|
|
8207
|
+
question: stringValue2(row.question),
|
|
8208
|
+
answer: stringValue2(row.answer),
|
|
7929
8209
|
is_other: Boolean(row.is_other)
|
|
7930
8210
|
};
|
|
7931
8211
|
})
|
|
@@ -7945,7 +8225,7 @@ function applyPolicyDenied(state, data) {
|
|
|
7945
8225
|
...policyMsg,
|
|
7946
8226
|
content: `${policyMsg.content}
|
|
7947
8227
|
|
|
7948
|
-
**Policy denied**: ${
|
|
8228
|
+
**Policy denied**: ${stringValue2(data.reason) || "Action blocked by governance policy."}`,
|
|
7949
8229
|
status: "error"
|
|
7950
8230
|
};
|
|
7951
8231
|
}
|
|
@@ -7997,7 +8277,7 @@ function objectValue(value) {
|
|
|
7997
8277
|
}
|
|
7998
8278
|
return void 0;
|
|
7999
8279
|
}
|
|
8000
|
-
function
|
|
8280
|
+
function stringValue2(value) {
|
|
8001
8281
|
return typeof value === "string" ? value : "";
|
|
8002
8282
|
}
|
|
8003
8283
|
function numberValue(value) {
|
|
@@ -8231,6 +8511,7 @@ function useAgentChatRuntime({
|
|
|
8231
8511
|
}
|
|
8232
8512
|
}, [adapter, sessionId]);
|
|
8233
8513
|
return {
|
|
8514
|
+
state,
|
|
8234
8515
|
session,
|
|
8235
8516
|
messages: state.messages,
|
|
8236
8517
|
isRunning: state.isRunning,
|
|
@@ -8282,6 +8563,7 @@ function AgentChat({
|
|
|
8282
8563
|
const isReadOnlySession = isScheduledRunSession(runtime.session);
|
|
8283
8564
|
const effectiveDisabled = disabled || isReadOnlySession;
|
|
8284
8565
|
const disabledReason = isReadOnlySession ? "Scheduled run is read-only" : void 0;
|
|
8566
|
+
const browserState = runtime.state.browser;
|
|
8285
8567
|
useEffect(() => {
|
|
8286
8568
|
onMessagesChange?.(runtime.messages);
|
|
8287
8569
|
}, [onMessagesChange, runtime.messages]);
|
|
@@ -8318,19 +8600,29 @@ function AgentChat({
|
|
|
8318
8600
|
retryIndicator: runtime.retryIndicator
|
|
8319
8601
|
}
|
|
8320
8602
|
) }),
|
|
8321
|
-
/* @__PURE__ */
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
|
|
8603
|
+
/* @__PURE__ */ jsxs("div", { "data-testid": "right-stack", className: "flex min-h-0 shrink-0 flex-col", children: [
|
|
8604
|
+
browserState !== null && sessionId && /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 border-b border-line", children: /* @__PURE__ */ jsx(
|
|
8605
|
+
BrowserPane,
|
|
8606
|
+
{
|
|
8607
|
+
sessionId,
|
|
8608
|
+
state: browserState,
|
|
8609
|
+
adapter
|
|
8610
|
+
}
|
|
8611
|
+
) }),
|
|
8612
|
+
/* @__PURE__ */ jsx(
|
|
8613
|
+
WorkspacePanel,
|
|
8614
|
+
{
|
|
8615
|
+
adapter,
|
|
8616
|
+
sessionId,
|
|
8617
|
+
selectedPath: workspacePath,
|
|
8618
|
+
onSelectedPathChange: setWorkspacePath,
|
|
8619
|
+
collapsed: workspaceCollapsed,
|
|
8620
|
+
onCollapsedChange: setWorkspaceCollapsed,
|
|
8621
|
+
refreshSignal: runtime.workspaceRefreshKey,
|
|
8622
|
+
disabled: effectiveDisabled
|
|
8623
|
+
}
|
|
8624
|
+
)
|
|
8625
|
+
] })
|
|
8334
8626
|
] }) })
|
|
8335
8627
|
}
|
|
8336
8628
|
);
|