@mastra/playground-ui 21.0.1-alpha.0 → 22.0.0-alpha.2
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/CHANGELOG.md +50 -0
- package/dist/index.cjs.js +2378 -335
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.css +133 -11
- package/dist/index.es.js +2365 -337
- package/dist/index.es.js.map +1 -1
- package/dist/src/domains/agents/components/agent-layout.d.ts +2 -1
- package/dist/src/domains/agents/components/agent-traces-panel.d.ts +9 -2
- package/dist/src/domains/agents/components/browser-view/agent-busy-overlay.d.ts +11 -0
- package/dist/src/domains/agents/components/browser-view/browser-sidebar-tab.d.ts +5 -0
- package/dist/src/domains/agents/components/browser-view/browser-thumbnail.d.ts +12 -0
- package/dist/src/domains/agents/components/browser-view/browser-tool-call-history.d.ts +9 -0
- package/dist/src/domains/agents/components/browser-view/browser-tool-call-item.d.ts +6 -0
- package/dist/src/domains/agents/components/browser-view/browser-view-frame.d.ts +15 -0
- package/dist/src/domains/agents/components/browser-view/browser-view-header.d.ts +15 -0
- package/dist/src/domains/agents/components/browser-view/browser-view-panel.d.ts +12 -0
- package/dist/src/domains/agents/components/browser-view/click-ripple-overlay.d.ts +16 -0
- package/dist/src/domains/agents/components/browser-view/index.d.ts +8 -0
- package/dist/src/domains/agents/context/browser-session-context.d.ts +62 -0
- package/dist/src/domains/agents/context/browser-tool-calls-context.d.ts +33 -0
- package/dist/src/domains/agents/context/index.d.ts +2 -0
- package/dist/src/domains/agents/hooks/use-browser-stream.d.ts +34 -0
- package/dist/src/domains/agents/hooks/use-click-ripple.d.ts +29 -0
- package/dist/src/domains/agents/hooks/use-close-browser.d.ts +12 -0
- package/dist/src/domains/agents/hooks/use-input-coordination.d.ts +20 -0
- package/dist/src/domains/agents/hooks/use-keyboard-interaction.d.ts +19 -0
- package/dist/src/domains/agents/hooks/use-mouse-interaction.d.ts +28 -0
- package/dist/src/domains/agents/index.d.ts +1 -0
- package/dist/src/domains/agents/utils/__tests__/coordinate-mapping.test.d.ts +1 -0
- package/dist/src/domains/agents/utils/coordinate-mapping.d.ts +68 -0
- package/dist/src/domains/agents/utils/key-mapping.d.ts +8 -0
- package/dist/src/domains/datasets/components/bulk-trace-review-dialog.d.ts +18 -0
- package/dist/src/domains/datasets/components/dataset-detail/dataset-item-form.d.ts +3 -1
- package/dist/src/domains/datasets/components/save-as-dataset-item-dialog.d.ts +5 -1
- package/dist/src/domains/metrics/hooks/use-avg-score-kpi-metrics.d.ts +1 -1
- package/dist/src/lib/ai-ui/thread.d.ts +2 -1
- package/package.json +9 -9
package/dist/index.cjs.js
CHANGED
|
@@ -61,25 +61,25 @@ const reactSyntaxHighlighter = require('@assistant-ui/react-syntax-highlighter')
|
|
|
61
61
|
const prism = require('react-syntax-highlighter/dist/cjs/styles/prism');
|
|
62
62
|
const clientJs = require('@mastra/client-js');
|
|
63
63
|
const di = require('@mastra/core/di');
|
|
64
|
-
const compatibility = require('./compatibility-BSEoV343.cjs');
|
|
65
64
|
const dnd = require('@hello-pangea/dnd');
|
|
66
65
|
const SwitchPrimitives = require('@radix-ui/react-switch');
|
|
67
66
|
const format = require('date-fns/format');
|
|
68
67
|
const HoverCard = require('@radix-ui/react-hover-card');
|
|
69
|
-
const AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
70
68
|
const semver = require('semver');
|
|
71
|
-
const DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
|
|
72
|
-
const features = require('@mastra/core/features');
|
|
73
|
-
const observability = require('@mastra/core/observability');
|
|
74
|
-
const storage = require('@mastra/core/storage');
|
|
75
69
|
const recharts = require('recharts');
|
|
70
|
+
const observability = require('@mastra/core/observability');
|
|
71
|
+
const DropdownMenuPrimitive = require('@radix-ui/react-dropdown-menu');
|
|
76
72
|
const Papa = require('papaparse');
|
|
73
|
+
const AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
|
|
77
74
|
const reactDom = require('react-dom');
|
|
78
75
|
const isToday = require('date-fns/isToday');
|
|
76
|
+
const features = require('@mastra/core/features');
|
|
77
|
+
const storage = require('@mastra/core/storage');
|
|
79
78
|
const cmdk = require('cmdk');
|
|
80
79
|
const merge = require('@codemirror/merge');
|
|
81
80
|
const state = require('@codemirror/state');
|
|
82
81
|
const reactSyntaxHighlighter$1 = require('react-syntax-highlighter');
|
|
82
|
+
const compatibility = require('./compatibility-BSEoV343.cjs');
|
|
83
83
|
|
|
84
84
|
function _interopNamespaceDefault(e) {
|
|
85
85
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
|
|
@@ -113,8 +113,8 @@ const SliderPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(SliderP
|
|
|
113
113
|
const RadixTabs__namespace = /*#__PURE__*/_interopNamespaceDefault(RadixTabs);
|
|
114
114
|
const SwitchPrimitives__namespace = /*#__PURE__*/_interopNamespaceDefault(SwitchPrimitives);
|
|
115
115
|
const HoverCard__namespace = /*#__PURE__*/_interopNamespaceDefault(HoverCard);
|
|
116
|
-
const AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(AlertDialogPrimitive);
|
|
117
116
|
const DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(DropdownMenuPrimitive);
|
|
117
|
+
const AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(AlertDialogPrimitive);
|
|
118
118
|
|
|
119
119
|
const defaultSettings = {
|
|
120
120
|
modelSettings: {
|
|
@@ -13995,11 +13995,69 @@ function useActivatedSkills() {
|
|
|
13995
13995
|
return React.useContext(ActivatedSkillsContext) ?? FALLBACK_CONTEXT;
|
|
13996
13996
|
}
|
|
13997
13997
|
|
|
13998
|
+
const BROWSER_TOOL_PREFIXES = ["browser_", "stagehand_"];
|
|
13999
|
+
function isBrowserTool(toolName) {
|
|
14000
|
+
return BROWSER_TOOL_PREFIXES.some((prefix) => toolName.startsWith(prefix));
|
|
14001
|
+
}
|
|
14002
|
+
function isBrowserToolError(result) {
|
|
14003
|
+
if (!result || typeof result !== "object") return false;
|
|
14004
|
+
const r = result;
|
|
14005
|
+
return r.success === false && typeof r.code === "string";
|
|
14006
|
+
}
|
|
14007
|
+
const BrowserToolCallsContext = React.createContext(null);
|
|
14008
|
+
function BrowserToolCallsProvider({ children }) {
|
|
14009
|
+
const [toolCallMap, setToolCallMap] = React.useState(/* @__PURE__ */ new Map());
|
|
14010
|
+
const registerToolCall = React.useCallback((entry) => {
|
|
14011
|
+
setToolCallMap((prev) => {
|
|
14012
|
+
const existing = prev.get(entry.toolCallId);
|
|
14013
|
+
if (existing && existing.result === entry.result && existing.status === entry.status) {
|
|
14014
|
+
return prev;
|
|
14015
|
+
}
|
|
14016
|
+
const next = new Map(prev);
|
|
14017
|
+
next.set(entry.toolCallId, existing ? { ...entry, timestamp: existing.timestamp } : entry);
|
|
14018
|
+
return next;
|
|
14019
|
+
});
|
|
14020
|
+
}, []);
|
|
14021
|
+
const toolCalls = React.useMemo(
|
|
14022
|
+
() => Array.from(toolCallMap.values()).sort((a, b) => a.timestamp - b.timestamp),
|
|
14023
|
+
[toolCallMap]
|
|
14024
|
+
);
|
|
14025
|
+
const value = React.useMemo(() => ({ toolCalls, registerToolCall }), [toolCalls, registerToolCall]);
|
|
14026
|
+
return /* @__PURE__ */ jsxRuntime.jsx(BrowserToolCallsContext.Provider, { value, children });
|
|
14027
|
+
}
|
|
14028
|
+
function useBrowserToolCalls() {
|
|
14029
|
+
const ctx = React.useContext(BrowserToolCallsContext);
|
|
14030
|
+
if (!ctx) {
|
|
14031
|
+
throw new Error("useBrowserToolCalls must be used within a BrowserToolCallsProvider");
|
|
14032
|
+
}
|
|
14033
|
+
return ctx;
|
|
14034
|
+
}
|
|
14035
|
+
function useBrowserToolCallsSafe() {
|
|
14036
|
+
return React.useContext(BrowserToolCallsContext);
|
|
14037
|
+
}
|
|
14038
|
+
|
|
13998
14039
|
const ToolFallback = ({ toolName, result, args, ...props }) => {
|
|
13999
14040
|
return /* @__PURE__ */ jsxRuntime.jsx(WorkflowRunProvider, { workflowId: "", withoutTimeTravel: true, children: /* @__PURE__ */ jsxRuntime.jsx(ToolFallbackInner, { toolName, result, args, ...props }) });
|
|
14000
14041
|
};
|
|
14001
14042
|
const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...props }) => {
|
|
14043
|
+
const browserCtx = useBrowserToolCallsSafe();
|
|
14044
|
+
const isBrowser = isBrowserTool(toolName);
|
|
14002
14045
|
const { activateSkill } = useActivatedSkills();
|
|
14046
|
+
React.useEffect(() => {
|
|
14047
|
+
if (!isBrowser || !browserCtx) return;
|
|
14048
|
+
let status = "pending";
|
|
14049
|
+
if (result !== void 0) {
|
|
14050
|
+
status = isBrowserToolError(result) ? "error" : "complete";
|
|
14051
|
+
}
|
|
14052
|
+
browserCtx.registerToolCall({
|
|
14053
|
+
toolCallId,
|
|
14054
|
+
toolName,
|
|
14055
|
+
args: typeof args === "object" ? args : {},
|
|
14056
|
+
result,
|
|
14057
|
+
status,
|
|
14058
|
+
timestamp: Date.now()
|
|
14059
|
+
});
|
|
14060
|
+
}, [isBrowser, toolCallId, toolName, args, result, browserCtx]);
|
|
14003
14061
|
React.useEffect(() => {
|
|
14004
14062
|
if (toolName !== "skill") return;
|
|
14005
14063
|
if (!args?.name) return;
|
|
@@ -14010,6 +14068,9 @@ const ToolFallbackInner = ({ toolName, result, args, metadata, toolCallId, ...pr
|
|
|
14010
14068
|
if (toolName === "mastra-memory-om-observation") {
|
|
14011
14069
|
return /* @__PURE__ */ jsxRuntime.jsx(ObservationMarkerBadge, { toolName, args, metadata });
|
|
14012
14070
|
}
|
|
14071
|
+
if (isBrowser && browserCtx) {
|
|
14072
|
+
return null;
|
|
14073
|
+
}
|
|
14013
14074
|
const isAgent = metadata?.mode === "network" && metadata.from === "AGENT" || toolName.startsWith("agent-");
|
|
14014
14075
|
const isWorkflow = metadata?.mode === "network" && metadata.from === "WORKFLOW" || toolName.startsWith("workflow-");
|
|
14015
14076
|
const isNetwork = metadata?.mode === "network";
|
|
@@ -15995,10 +16056,12 @@ const Avatar = ({ src, name, size = "sm", interactive = false }) => {
|
|
|
15995
16056
|
);
|
|
15996
16057
|
};
|
|
15997
16058
|
|
|
15998
|
-
const Thread = ({ agentName, agentId, hasMemory, hasModelList, hideModelSwitcher }) => {
|
|
16059
|
+
const Thread = ({ agentName, agentId, threadId, hasMemory, hasModelList, hideModelSwitcher }) => {
|
|
15999
16060
|
const areaRef = React.useRef(null);
|
|
16000
16061
|
const messagesContainerRef = React.useRef(null);
|
|
16001
16062
|
useAutoscroll(areaRef, { enabled: true });
|
|
16063
|
+
const { hasSession, viewMode, isInSidebar } = useBrowserSession();
|
|
16064
|
+
const showThumbnailInChat = hasSession && (viewMode === "collapsed" || viewMode === "expanded") && !isInSidebar;
|
|
16002
16065
|
const WrappedAssistantMessage = (props) => {
|
|
16003
16066
|
return /* @__PURE__ */ jsxRuntime.jsx(AssistantMessage, { ...props, hasModelList });
|
|
16004
16067
|
};
|
|
@@ -16023,6 +16086,7 @@ const Thread = ({ agentName, agentId, hasMemory, hasModelList, hideModelSwitcher
|
|
|
16023
16086
|
/* @__PURE__ */ jsxRuntime.jsx("div", {})
|
|
16024
16087
|
] })
|
|
16025
16088
|
] }),
|
|
16089
|
+
showThumbnailInChat && agentId && threadId && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-4 mb-2 max-w-3xl w-full mx-auto", children: /* @__PURE__ */ jsxRuntime.jsx(BrowserThumbnail, { agentName }) }),
|
|
16026
16090
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16027
16091
|
Composer,
|
|
16028
16092
|
{
|
|
@@ -16240,6 +16304,243 @@ function useWorkingMemory() {
|
|
|
16240
16304
|
return ctx;
|
|
16241
16305
|
}
|
|
16242
16306
|
|
|
16307
|
+
function useCloseBrowser() {
|
|
16308
|
+
return reactQuery.useMutation({
|
|
16309
|
+
mutationFn: async ({ agentId, threadId }) => {
|
|
16310
|
+
const response = await fetch(`/api/agents/${agentId}/browser/close`, {
|
|
16311
|
+
method: "POST",
|
|
16312
|
+
headers: { "Content-Type": "application/json" },
|
|
16313
|
+
body: JSON.stringify({ threadId })
|
|
16314
|
+
});
|
|
16315
|
+
if (!response.ok) {
|
|
16316
|
+
throw new Error(`Failed to close browser: ${response.status}`);
|
|
16317
|
+
}
|
|
16318
|
+
return { success: true };
|
|
16319
|
+
},
|
|
16320
|
+
onError: (err) => {
|
|
16321
|
+
console.error("[useCloseBrowser] Error closing browser:", err);
|
|
16322
|
+
}
|
|
16323
|
+
});
|
|
16324
|
+
}
|
|
16325
|
+
|
|
16326
|
+
const BrowserSessionContext = React.createContext(null);
|
|
16327
|
+
function BrowserSessionProvider({ children, agentId, threadId }) {
|
|
16328
|
+
const [hasSession, setHasSession] = React.useState(false);
|
|
16329
|
+
const [viewMode, setViewModeState] = React.useState("collapsed");
|
|
16330
|
+
const [status, setStatusState] = React.useState("idle");
|
|
16331
|
+
const [currentUrl, setCurrentUrlState] = React.useState(null);
|
|
16332
|
+
const [latestFrame, setLatestFrameState] = React.useState(null);
|
|
16333
|
+
const [viewport, setViewport] = React.useState(null);
|
|
16334
|
+
const wsRef = React.useRef(null);
|
|
16335
|
+
const reconnectAttemptRef = React.useRef(0);
|
|
16336
|
+
const reconnectTimeoutRef = React.useRef(null);
|
|
16337
|
+
const currentConnectionRef = React.useRef(null);
|
|
16338
|
+
const maxReconnectAttempts = 5;
|
|
16339
|
+
const clearReconnectTimeout = React.useCallback(() => {
|
|
16340
|
+
if (reconnectTimeoutRef.current) {
|
|
16341
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
16342
|
+
reconnectTimeoutRef.current = null;
|
|
16343
|
+
}
|
|
16344
|
+
}, []);
|
|
16345
|
+
const disconnect = React.useCallback(() => {
|
|
16346
|
+
clearReconnectTimeout();
|
|
16347
|
+
currentConnectionRef.current = null;
|
|
16348
|
+
if (wsRef.current) {
|
|
16349
|
+
wsRef.current.close();
|
|
16350
|
+
wsRef.current = null;
|
|
16351
|
+
}
|
|
16352
|
+
setHasSession(false);
|
|
16353
|
+
setStatusState("idle");
|
|
16354
|
+
setCurrentUrlState(null);
|
|
16355
|
+
setLatestFrameState(null);
|
|
16356
|
+
setViewport(null);
|
|
16357
|
+
}, [clearReconnectTimeout]);
|
|
16358
|
+
const sendMessage = React.useCallback((data) => {
|
|
16359
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
16360
|
+
wsRef.current.send(data);
|
|
16361
|
+
}
|
|
16362
|
+
}, []);
|
|
16363
|
+
const intentionalCloseRef = React.useRef(false);
|
|
16364
|
+
const connect = React.useCallback(() => {
|
|
16365
|
+
if (!agentId || !threadId) return;
|
|
16366
|
+
if (currentConnectionRef.current?.agentId === agentId && currentConnectionRef.current?.threadId === threadId && wsRef.current?.readyState === WebSocket.OPEN) {
|
|
16367
|
+
return;
|
|
16368
|
+
}
|
|
16369
|
+
clearReconnectTimeout();
|
|
16370
|
+
if (wsRef.current) {
|
|
16371
|
+
intentionalCloseRef.current = true;
|
|
16372
|
+
wsRef.current.close();
|
|
16373
|
+
wsRef.current = null;
|
|
16374
|
+
}
|
|
16375
|
+
currentConnectionRef.current = { agentId, threadId };
|
|
16376
|
+
setStatusState("connecting");
|
|
16377
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
16378
|
+
const wsUrl = `${protocol}//${window.location.host}/browser/${agentId}/stream?threadId=${encodeURIComponent(threadId)}`;
|
|
16379
|
+
try {
|
|
16380
|
+
const ws = new WebSocket(wsUrl);
|
|
16381
|
+
intentionalCloseRef.current = false;
|
|
16382
|
+
wsRef.current = ws;
|
|
16383
|
+
ws.onopen = () => {
|
|
16384
|
+
setStatusState("connected");
|
|
16385
|
+
reconnectAttemptRef.current = 0;
|
|
16386
|
+
};
|
|
16387
|
+
ws.onmessage = (event) => {
|
|
16388
|
+
const data = event.data;
|
|
16389
|
+
if (data.startsWith("{")) {
|
|
16390
|
+
try {
|
|
16391
|
+
const parsed = JSON.parse(data);
|
|
16392
|
+
if (parsed.status) {
|
|
16393
|
+
switch (parsed.status) {
|
|
16394
|
+
case "browser_starting":
|
|
16395
|
+
setStatusState("browser_starting");
|
|
16396
|
+
break;
|
|
16397
|
+
case "streaming":
|
|
16398
|
+
setStatusState("streaming");
|
|
16399
|
+
setHasSession(true);
|
|
16400
|
+
break;
|
|
16401
|
+
case "browser_closed":
|
|
16402
|
+
setStatusState("browser_closed");
|
|
16403
|
+
setHasSession(false);
|
|
16404
|
+
setViewModeState("collapsed");
|
|
16405
|
+
break;
|
|
16406
|
+
case "stopped":
|
|
16407
|
+
setStatusState("disconnected");
|
|
16408
|
+
break;
|
|
16409
|
+
case "error":
|
|
16410
|
+
setStatusState("error");
|
|
16411
|
+
setHasSession(false);
|
|
16412
|
+
break;
|
|
16413
|
+
}
|
|
16414
|
+
}
|
|
16415
|
+
if (parsed.url) {
|
|
16416
|
+
setCurrentUrlState(parsed.url);
|
|
16417
|
+
}
|
|
16418
|
+
if (parsed.viewport) {
|
|
16419
|
+
setViewport(parsed.viewport);
|
|
16420
|
+
}
|
|
16421
|
+
} catch {
|
|
16422
|
+
setLatestFrameState(data);
|
|
16423
|
+
}
|
|
16424
|
+
} else {
|
|
16425
|
+
setLatestFrameState(data);
|
|
16426
|
+
setStatusState((prev) => prev !== "streaming" ? "streaming" : prev);
|
|
16427
|
+
setHasSession(true);
|
|
16428
|
+
}
|
|
16429
|
+
};
|
|
16430
|
+
ws.onerror = () => {
|
|
16431
|
+
};
|
|
16432
|
+
ws.onclose = (event) => {
|
|
16433
|
+
if (wsRef.current !== ws) return;
|
|
16434
|
+
wsRef.current = null;
|
|
16435
|
+
if (!intentionalCloseRef.current && !event.wasClean && reconnectAttemptRef.current < maxReconnectAttempts) {
|
|
16436
|
+
reconnectAttemptRef.current += 1;
|
|
16437
|
+
const delay = Math.min(1e3 * Math.pow(2, reconnectAttemptRef.current - 1), 1e4);
|
|
16438
|
+
setStatusState("disconnected");
|
|
16439
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
16440
|
+
connect();
|
|
16441
|
+
}, delay);
|
|
16442
|
+
} else if (reconnectAttemptRef.current >= maxReconnectAttempts) {
|
|
16443
|
+
setStatusState("error");
|
|
16444
|
+
}
|
|
16445
|
+
};
|
|
16446
|
+
} catch {
|
|
16447
|
+
setStatusState("error");
|
|
16448
|
+
}
|
|
16449
|
+
}, [agentId, threadId, clearReconnectTimeout]);
|
|
16450
|
+
React.useEffect(() => {
|
|
16451
|
+
if (agentId && threadId) {
|
|
16452
|
+
connect();
|
|
16453
|
+
}
|
|
16454
|
+
return () => {
|
|
16455
|
+
disconnect();
|
|
16456
|
+
};
|
|
16457
|
+
}, [agentId, threadId, connect, disconnect]);
|
|
16458
|
+
React.useEffect(() => {
|
|
16459
|
+
const handleVisibilityChange = () => {
|
|
16460
|
+
if (document.visibilityState === "visible" && status === "disconnected" && agentId && threadId) {
|
|
16461
|
+
reconnectAttemptRef.current = 0;
|
|
16462
|
+
connect();
|
|
16463
|
+
}
|
|
16464
|
+
};
|
|
16465
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
16466
|
+
return () => {
|
|
16467
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
16468
|
+
};
|
|
16469
|
+
}, [status, agentId, threadId, connect]);
|
|
16470
|
+
const setViewMode = React.useCallback((mode) => {
|
|
16471
|
+
setViewModeState(mode);
|
|
16472
|
+
}, []);
|
|
16473
|
+
const show = React.useCallback(() => {
|
|
16474
|
+
setViewModeState("modal");
|
|
16475
|
+
}, []);
|
|
16476
|
+
const hide = React.useCallback(() => {
|
|
16477
|
+
setViewModeState("collapsed");
|
|
16478
|
+
}, []);
|
|
16479
|
+
const endSession = React.useCallback(() => {
|
|
16480
|
+
setHasSession(false);
|
|
16481
|
+
setViewModeState("collapsed");
|
|
16482
|
+
setLatestFrameState(null);
|
|
16483
|
+
}, []);
|
|
16484
|
+
const closeBrowserMutation = useCloseBrowser();
|
|
16485
|
+
const closeBrowser = React.useCallback(async () => {
|
|
16486
|
+
if (closeBrowserMutation.isPending || !agentId) return;
|
|
16487
|
+
try {
|
|
16488
|
+
await closeBrowserMutation.mutateAsync({ agentId, threadId });
|
|
16489
|
+
endSession();
|
|
16490
|
+
} catch {
|
|
16491
|
+
}
|
|
16492
|
+
}, [agentId, threadId, closeBrowserMutation, endSession]);
|
|
16493
|
+
const isClosing = closeBrowserMutation.isPending;
|
|
16494
|
+
const value = React.useMemo(
|
|
16495
|
+
() => ({
|
|
16496
|
+
hasSession,
|
|
16497
|
+
viewMode,
|
|
16498
|
+
isPanelOpen: viewMode === "modal",
|
|
16499
|
+
isInSidebar: viewMode === "sidebar",
|
|
16500
|
+
isActive: hasSession,
|
|
16501
|
+
// backward compat - reflects session activity, not view mode
|
|
16502
|
+
status,
|
|
16503
|
+
currentUrl,
|
|
16504
|
+
latestFrame,
|
|
16505
|
+
viewport,
|
|
16506
|
+
isClosing,
|
|
16507
|
+
setViewMode,
|
|
16508
|
+
show,
|
|
16509
|
+
hide,
|
|
16510
|
+
endSession,
|
|
16511
|
+
closeBrowser,
|
|
16512
|
+
sendMessage,
|
|
16513
|
+
connect,
|
|
16514
|
+
disconnect
|
|
16515
|
+
}),
|
|
16516
|
+
[
|
|
16517
|
+
hasSession,
|
|
16518
|
+
viewMode,
|
|
16519
|
+
status,
|
|
16520
|
+
currentUrl,
|
|
16521
|
+
latestFrame,
|
|
16522
|
+
viewport,
|
|
16523
|
+
isClosing,
|
|
16524
|
+
setViewMode,
|
|
16525
|
+
show,
|
|
16526
|
+
hide,
|
|
16527
|
+
endSession,
|
|
16528
|
+
closeBrowser,
|
|
16529
|
+
sendMessage,
|
|
16530
|
+
connect,
|
|
16531
|
+
disconnect
|
|
16532
|
+
]
|
|
16533
|
+
);
|
|
16534
|
+
return /* @__PURE__ */ jsxRuntime.jsx(BrowserSessionContext.Provider, { value, children });
|
|
16535
|
+
}
|
|
16536
|
+
function useBrowserSession() {
|
|
16537
|
+
const ctx = React.useContext(BrowserSessionContext);
|
|
16538
|
+
if (!ctx) {
|
|
16539
|
+
throw new Error("useBrowserSession must be used within a BrowserSessionProvider");
|
|
16540
|
+
}
|
|
16541
|
+
return ctx;
|
|
16542
|
+
}
|
|
16543
|
+
|
|
16243
16544
|
const ObservationalMemoryContext = React.createContext(null);
|
|
16244
16545
|
function ObservationalMemoryProvider({ children }) {
|
|
16245
16546
|
const [isObservingFromStream, setIsObservingFromStream] = React.useState(false);
|
|
@@ -17844,6 +18145,7 @@ const AgentChat = ({
|
|
|
17844
18145
|
agentName: agentName ?? "",
|
|
17845
18146
|
hasMemory: memory,
|
|
17846
18147
|
agentId,
|
|
18148
|
+
threadId,
|
|
17847
18149
|
hasModelList: Boolean(modelList),
|
|
17848
18150
|
hideModelSwitcher
|
|
17849
18151
|
}
|
|
@@ -19525,6 +19827,8 @@ function getShortId(id) {
|
|
|
19525
19827
|
function SaveAsDatasetItemDialog({
|
|
19526
19828
|
initialInput,
|
|
19527
19829
|
initialGroundTruth,
|
|
19830
|
+
initialTrajectory,
|
|
19831
|
+
trajectoryLoading,
|
|
19528
19832
|
breadcrumb,
|
|
19529
19833
|
isOpen,
|
|
19530
19834
|
onClose,
|
|
@@ -19534,15 +19838,30 @@ function SaveAsDatasetItemDialog({
|
|
|
19534
19838
|
const [selectedDatasetId, setSelectedDatasetId] = React.useState("");
|
|
19535
19839
|
const [input, setInput] = React.useState("");
|
|
19536
19840
|
const [groundTruth, setGroundTruth] = React.useState("");
|
|
19841
|
+
const [expectedTrajectory, setExpectedTrajectory] = React.useState("");
|
|
19537
19842
|
const { data, isLoading: isDatasetsLoading } = useDatasets();
|
|
19538
19843
|
const { addItem } = useDatasetMutations();
|
|
19539
19844
|
const datasets = data?.datasets ?? [];
|
|
19845
|
+
const prevOpenRef = React.useRef(false);
|
|
19846
|
+
const trajectorySeededRef = React.useRef(false);
|
|
19540
19847
|
React.useEffect(() => {
|
|
19541
|
-
if (isOpen) {
|
|
19848
|
+
if (isOpen && !prevOpenRef.current) {
|
|
19542
19849
|
setInput(initialInput);
|
|
19543
19850
|
setGroundTruth(initialGroundTruth);
|
|
19851
|
+
setExpectedTrajectory(initialTrajectory ?? "");
|
|
19852
|
+
trajectorySeededRef.current = !!initialTrajectory;
|
|
19544
19853
|
}
|
|
19545
|
-
|
|
19854
|
+
prevOpenRef.current = isOpen;
|
|
19855
|
+
if (!isOpen) {
|
|
19856
|
+
trajectorySeededRef.current = false;
|
|
19857
|
+
}
|
|
19858
|
+
}, [isOpen, initialInput, initialGroundTruth, initialTrajectory]);
|
|
19859
|
+
React.useEffect(() => {
|
|
19860
|
+
if (isOpen && initialTrajectory && !trajectorySeededRef.current) {
|
|
19861
|
+
setExpectedTrajectory(initialTrajectory);
|
|
19862
|
+
trajectorySeededRef.current = true;
|
|
19863
|
+
}
|
|
19864
|
+
}, [isOpen, initialTrajectory]);
|
|
19546
19865
|
const handleSubmit = async (e) => {
|
|
19547
19866
|
e.preventDefault();
|
|
19548
19867
|
if (!selectedDatasetId) {
|
|
@@ -19565,11 +19884,21 @@ function SaveAsDatasetItemDialog({
|
|
|
19565
19884
|
return;
|
|
19566
19885
|
}
|
|
19567
19886
|
}
|
|
19887
|
+
let parsedTrajectory;
|
|
19888
|
+
if (expectedTrajectory.trim()) {
|
|
19889
|
+
try {
|
|
19890
|
+
parsedTrajectory = JSON.parse(expectedTrajectory);
|
|
19891
|
+
} catch {
|
|
19892
|
+
toast.error("Expected Trajectory must be valid JSON");
|
|
19893
|
+
return;
|
|
19894
|
+
}
|
|
19895
|
+
}
|
|
19568
19896
|
try {
|
|
19569
19897
|
await addItem.mutateAsync({
|
|
19570
19898
|
datasetId: selectedDatasetId,
|
|
19571
19899
|
input: parsedInput,
|
|
19572
19900
|
groundTruth: parsedGroundTruth,
|
|
19901
|
+
expectedTrajectory: parsedTrajectory,
|
|
19573
19902
|
...source ? { source } : {}
|
|
19574
19903
|
});
|
|
19575
19904
|
const targetDataset = datasets.find((d) => d.id === selectedDatasetId);
|
|
@@ -19577,6 +19906,7 @@ function SaveAsDatasetItemDialog({
|
|
|
19577
19906
|
setSelectedDatasetId("");
|
|
19578
19907
|
setInput("{}");
|
|
19579
19908
|
setGroundTruth("");
|
|
19909
|
+
setExpectedTrajectory("");
|
|
19580
19910
|
onClose();
|
|
19581
19911
|
} catch (error) {
|
|
19582
19912
|
toast.error(`Failed to save item: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
@@ -19632,6 +19962,18 @@ function SaveAsDatasetItemDialog({
|
|
|
19632
19962
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "item-ground-truth", children: "Ground Truth (JSON, optional)" }),
|
|
19633
19963
|
/* @__PURE__ */ jsxRuntime.jsx(CodeEditor, { value: groundTruth, onChange: setGroundTruth, showCopyButton: false, className: "min-h-[80px]" })
|
|
19634
19964
|
] }),
|
|
19965
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
19966
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "item-trajectory", children: "Expected Trajectory (JSON, optional)" }),
|
|
19967
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19968
|
+
CodeEditor,
|
|
19969
|
+
{
|
|
19970
|
+
value: expectedTrajectory,
|
|
19971
|
+
onChange: setExpectedTrajectory,
|
|
19972
|
+
showCopyButton: false,
|
|
19973
|
+
className: "min-h-[80px]"
|
|
19974
|
+
}
|
|
19975
|
+
)
|
|
19976
|
+
] }),
|
|
19635
19977
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 pt-4", children: [
|
|
19636
19978
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "outline", onClick: handleCancel, children: "Cancel" }),
|
|
19637
19979
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -19639,8 +19981,8 @@ function SaveAsDatasetItemDialog({
|
|
|
19639
19981
|
{
|
|
19640
19982
|
type: "submit",
|
|
19641
19983
|
variant: "light",
|
|
19642
|
-
disabled: addItem.isPending || !selectedDatasetId || datasets.length === 0,
|
|
19643
|
-
children: addItem.isPending ? "Saving..." : "Save Item"
|
|
19984
|
+
disabled: addItem.isPending || trajectoryLoading || !selectedDatasetId || datasets.length === 0,
|
|
19985
|
+
children: addItem.isPending ? "Saving..." : trajectoryLoading ? "Loading trajectory..." : "Save Item"
|
|
19644
19986
|
}
|
|
19645
19987
|
)
|
|
19646
19988
|
] })
|
|
@@ -19774,8 +20116,9 @@ function ScoreDialog({
|
|
|
19774
20116
|
usageContext = "scorerPage"
|
|
19775
20117
|
}) {
|
|
19776
20118
|
const [datasetDialogOpen, setDatasetDialogOpen] = React.useState(false);
|
|
19777
|
-
const { Link } = useLinkComponent();
|
|
20119
|
+
const { Link, paths } = useLinkComponent();
|
|
19778
20120
|
const isCodeBased = isCodeBasedScorer$1(score);
|
|
20121
|
+
const scorerDetailHref = score?.scorerId && score?.entityId ? `${paths.scorerLink(score.scorerId)}?entity=${encodeURIComponent(score.entityId)}&scoreId=${encodeURIComponent(score.id)}` : void 0;
|
|
19779
20122
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
19780
20123
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
19781
20124
|
SideDialog,
|
|
@@ -19838,7 +20181,7 @@ function ScoreDialog({
|
|
|
19838
20181
|
...usageContext === "SpanDialog" ? [
|
|
19839
20182
|
{
|
|
19840
20183
|
label: "Scorer",
|
|
19841
|
-
value: score?.scorer?.name || "-",
|
|
20184
|
+
value: scorerDetailHref ? /* @__PURE__ */ jsxRuntime.jsx(Link, { href: scorerDetailHref, children: score?.scorer?.name || "-" }) : score?.scorer?.name || "-",
|
|
19842
20185
|
key: "scorer-name"
|
|
19843
20186
|
}
|
|
19844
20187
|
] : [],
|
|
@@ -22927,6 +23270,779 @@ const AgentToolPanel = ({ toolId, agentId }) => {
|
|
|
22927
23270
|
);
|
|
22928
23271
|
};
|
|
22929
23272
|
|
|
23273
|
+
const TOOL_DISPLAY_NAMES$1 = {
|
|
23274
|
+
// AgentBrowser tools
|
|
23275
|
+
browser_goto: "Go to",
|
|
23276
|
+
browser_click: "Click",
|
|
23277
|
+
browser_type: "Type",
|
|
23278
|
+
browser_scroll: "Scroll",
|
|
23279
|
+
browser_snapshot: "Snapshot",
|
|
23280
|
+
browser_close: "Close",
|
|
23281
|
+
browser_select: "Select",
|
|
23282
|
+
browser_press: "Press",
|
|
23283
|
+
browser_hover: "Hover",
|
|
23284
|
+
browser_back: "Back",
|
|
23285
|
+
browser_dialog: "Dialog",
|
|
23286
|
+
browser_wait: "Wait",
|
|
23287
|
+
browser_tabs: "Tabs",
|
|
23288
|
+
browser_drag: "Drag",
|
|
23289
|
+
browser_evaluate: "Evaluate",
|
|
23290
|
+
// StagehandBrowser tools
|
|
23291
|
+
stagehand_navigate: "Navigate",
|
|
23292
|
+
stagehand_act: "Act",
|
|
23293
|
+
stagehand_extract: "Extract",
|
|
23294
|
+
stagehand_observe: "Observe",
|
|
23295
|
+
stagehand_close: "Close",
|
|
23296
|
+
stagehand_tabs: "Tabs"
|
|
23297
|
+
};
|
|
23298
|
+
const KEY_ARG_MAP = {
|
|
23299
|
+
// AgentBrowser tools
|
|
23300
|
+
browser_goto: "url",
|
|
23301
|
+
browser_click: "ref",
|
|
23302
|
+
browser_type: "text",
|
|
23303
|
+
browser_scroll: "direction",
|
|
23304
|
+
browser_close: "reason",
|
|
23305
|
+
browser_select: "value",
|
|
23306
|
+
browser_press: "key",
|
|
23307
|
+
browser_hover: "ref",
|
|
23308
|
+
browser_dialog: "action",
|
|
23309
|
+
browser_wait: "time",
|
|
23310
|
+
browser_tabs: "action",
|
|
23311
|
+
browser_drag: "sourceRef",
|
|
23312
|
+
browser_evaluate: "expression",
|
|
23313
|
+
// StagehandBrowser tools
|
|
23314
|
+
stagehand_navigate: "url",
|
|
23315
|
+
stagehand_act: "action",
|
|
23316
|
+
stagehand_extract: "instruction",
|
|
23317
|
+
stagehand_observe: "instruction",
|
|
23318
|
+
stagehand_tabs: "action"
|
|
23319
|
+
};
|
|
23320
|
+
function getDisplayName(toolName) {
|
|
23321
|
+
if (TOOL_DISPLAY_NAMES$1[toolName]) {
|
|
23322
|
+
return TOOL_DISPLAY_NAMES$1[toolName];
|
|
23323
|
+
}
|
|
23324
|
+
return toolName.replace(/^(browser_|stagehand_)/, "");
|
|
23325
|
+
}
|
|
23326
|
+
function getKeyArgSummary(toolName, args) {
|
|
23327
|
+
const key = KEY_ARG_MAP[toolName];
|
|
23328
|
+
if (!key) return null;
|
|
23329
|
+
const value = args[key];
|
|
23330
|
+
if (value === void 0 || value === null) return null;
|
|
23331
|
+
const str = String(value);
|
|
23332
|
+
return str.length > 50 ? `${str.slice(0, 47)}...` : str;
|
|
23333
|
+
}
|
|
23334
|
+
function BrowserToolCallItem({ entry }) {
|
|
23335
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
23336
|
+
const displayName = getDisplayName(entry.toolName);
|
|
23337
|
+
const keyArg = getKeyArgSummary(entry.toolName, entry.args);
|
|
23338
|
+
const { __mastraMetadata: _, ...displayArgs } = entry.args;
|
|
23339
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-border1 last:border-b-0", children: [
|
|
23340
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23341
|
+
"button",
|
|
23342
|
+
{
|
|
23343
|
+
type: "button",
|
|
23344
|
+
onClick: () => setIsExpanded((prev) => !prev),
|
|
23345
|
+
"aria-expanded": isExpanded,
|
|
23346
|
+
className: "flex items-center gap-2 w-full px-3 py-0.5 text-left hover:bg-surface3 transition-colors",
|
|
23347
|
+
children: [
|
|
23348
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23349
|
+
lucideReact.ChevronRight,
|
|
23350
|
+
{
|
|
23351
|
+
className: cn("h-3 w-3 text-neutral3 transition-transform shrink-0", isExpanded && "rotate-90")
|
|
23352
|
+
}
|
|
23353
|
+
),
|
|
23354
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusDot, { status: entry.status }),
|
|
23355
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-neutral6 shrink-0", children: displayName }),
|
|
23356
|
+
keyArg && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-neutral3 truncate", children: keyArg })
|
|
23357
|
+
]
|
|
23358
|
+
}
|
|
23359
|
+
),
|
|
23360
|
+
isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pb-2 space-y-2", children: [
|
|
23361
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
23362
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-neutral4 pb-1", children: "Arguments" }),
|
|
23363
|
+
/* @__PURE__ */ jsxRuntime.jsx(CodeEditor, { data: displayArgs, "data-testid": "browser-tool-args" })
|
|
23364
|
+
] }),
|
|
23365
|
+
entry.result !== void 0 && entry.result !== null && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
23366
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-neutral4 pb-1", children: "Result" }),
|
|
23367
|
+
typeof entry.result === "string" ? /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "whitespace-pre text-xs bg-surface4 p-2 rounded-md overflow-x-auto max-h-40 overflow-y-auto", children: entry.result }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23368
|
+
CodeEditor,
|
|
23369
|
+
{
|
|
23370
|
+
data: entry.result,
|
|
23371
|
+
"data-testid": "browser-tool-result"
|
|
23372
|
+
}
|
|
23373
|
+
)
|
|
23374
|
+
] })
|
|
23375
|
+
] })
|
|
23376
|
+
] });
|
|
23377
|
+
}
|
|
23378
|
+
function StatusDot({ status }) {
|
|
23379
|
+
switch (status) {
|
|
23380
|
+
case "pending":
|
|
23381
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 text-neutral4 animate-spin shrink-0" });
|
|
23382
|
+
case "complete":
|
|
23383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 text-green-500 shrink-0" });
|
|
23384
|
+
case "error":
|
|
23385
|
+
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3 text-red-500 shrink-0" });
|
|
23386
|
+
}
|
|
23387
|
+
}
|
|
23388
|
+
|
|
23389
|
+
function BrowserToolCallHistory({ className }) {
|
|
23390
|
+
const { toolCalls } = useBrowserToolCalls();
|
|
23391
|
+
const [isExpanded, setIsExpanded] = React.useState(true);
|
|
23392
|
+
const listRef = React.useRef(null);
|
|
23393
|
+
React.useEffect(() => {
|
|
23394
|
+
if (isExpanded && listRef.current) {
|
|
23395
|
+
listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
23396
|
+
}
|
|
23397
|
+
}, [toolCalls.length, isExpanded]);
|
|
23398
|
+
if (toolCalls.length === 0) return null;
|
|
23399
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col overflow-hidden", className), children: [
|
|
23400
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
23401
|
+
"button",
|
|
23402
|
+
{
|
|
23403
|
+
type: "button",
|
|
23404
|
+
onClick: () => setIsExpanded((prev) => !prev),
|
|
23405
|
+
"aria-expanded": isExpanded,
|
|
23406
|
+
className: "flex items-center gap-2 w-full px-3 py-1 text-left hover:bg-surface3 transition-colors shrink-0",
|
|
23407
|
+
children: [
|
|
23408
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn("h-3.5 w-3.5 text-neutral3 transition-transform", isExpanded ? "rotate-180" : "") }),
|
|
23409
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-neutral4", children: [
|
|
23410
|
+
"Browser Actions (",
|
|
23411
|
+
toolCalls.length,
|
|
23412
|
+
")"
|
|
23413
|
+
] })
|
|
23414
|
+
]
|
|
23415
|
+
}
|
|
23416
|
+
),
|
|
23417
|
+
isExpanded && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: listRef, className: "flex-1 overflow-y-auto bg-surface1", children: toolCalls.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(BrowserToolCallItem, { entry }, entry.toolCallId)) })
|
|
23418
|
+
] });
|
|
23419
|
+
}
|
|
23420
|
+
|
|
23421
|
+
const MAX_RIPPLES = 10;
|
|
23422
|
+
function useClickRipple(options) {
|
|
23423
|
+
const [ripples, setRipples] = React.useState([]);
|
|
23424
|
+
const idRef = React.useRef(0);
|
|
23425
|
+
const viewportRef = React.useRef(options.viewport);
|
|
23426
|
+
React.useEffect(() => {
|
|
23427
|
+
viewportRef.current = options.viewport;
|
|
23428
|
+
}, [options.viewport]);
|
|
23429
|
+
const removeRipple = React.useCallback((id) => {
|
|
23430
|
+
setRipples((prev) => prev.filter((r) => r.id !== id));
|
|
23431
|
+
}, []);
|
|
23432
|
+
React.useEffect(() => {
|
|
23433
|
+
if (!options.enabled || !options.imgRef.current) {
|
|
23434
|
+
return;
|
|
23435
|
+
}
|
|
23436
|
+
const imgElement = options.imgRef.current;
|
|
23437
|
+
function handleMouseDown(e) {
|
|
23438
|
+
if (e.button !== 0) return;
|
|
23439
|
+
const viewport = viewportRef.current;
|
|
23440
|
+
if (!viewport) return;
|
|
23441
|
+
const rect = imgElement.getBoundingClientRect();
|
|
23442
|
+
const relX = e.clientX - rect.left;
|
|
23443
|
+
const relY = e.clientY - rect.top;
|
|
23444
|
+
const scale = Math.min(rect.width / viewport.width, rect.height / viewport.height);
|
|
23445
|
+
const renderedWidth = viewport.width * scale;
|
|
23446
|
+
const renderedHeight = viewport.height * scale;
|
|
23447
|
+
const offsetX = (rect.width - renderedWidth) / 2;
|
|
23448
|
+
const offsetY = (rect.height - renderedHeight) / 2;
|
|
23449
|
+
const imageX = relX - offsetX;
|
|
23450
|
+
const imageY = relY - offsetY;
|
|
23451
|
+
if (imageX < 0 || imageY < 0 || imageX > renderedWidth || imageY > renderedHeight) {
|
|
23452
|
+
return;
|
|
23453
|
+
}
|
|
23454
|
+
setRipples((prev) => {
|
|
23455
|
+
if (prev.length >= MAX_RIPPLES) return prev;
|
|
23456
|
+
const id = ++idRef.current;
|
|
23457
|
+
return [...prev, { id, x: relX, y: relY }];
|
|
23458
|
+
});
|
|
23459
|
+
}
|
|
23460
|
+
imgElement.addEventListener("mousedown", handleMouseDown);
|
|
23461
|
+
return () => {
|
|
23462
|
+
imgElement.removeEventListener("mousedown", handleMouseDown);
|
|
23463
|
+
};
|
|
23464
|
+
}, [options.enabled, options.imgRef]);
|
|
23465
|
+
return { ripples, removeRipple };
|
|
23466
|
+
}
|
|
23467
|
+
|
|
23468
|
+
function useInputCoordination() {
|
|
23469
|
+
const { toolCalls } = useBrowserToolCalls();
|
|
23470
|
+
return React.useMemo(() => {
|
|
23471
|
+
const pendingCalls = toolCalls.filter((tc) => tc.status === "pending");
|
|
23472
|
+
const isAgentBusy = pendingCalls.length > 0;
|
|
23473
|
+
const activeToolName = isAgentBusy ? pendingCalls[0].toolName : null;
|
|
23474
|
+
return { isAgentBusy, activeToolName, pendingCount: pendingCalls.length };
|
|
23475
|
+
}, [toolCalls]);
|
|
23476
|
+
}
|
|
23477
|
+
|
|
23478
|
+
const LINE_HEIGHT_PX = 16;
|
|
23479
|
+
const MAX_DELTA = 500;
|
|
23480
|
+
function mapClientToViewport(clientX, clientY, elemRect, viewport) {
|
|
23481
|
+
const relX = clientX - elemRect.left;
|
|
23482
|
+
const relY = clientY - elemRect.top;
|
|
23483
|
+
const scale = Math.min(elemRect.width / viewport.width, elemRect.height / viewport.height);
|
|
23484
|
+
const renderedWidth = viewport.width * scale;
|
|
23485
|
+
const renderedHeight = viewport.height * scale;
|
|
23486
|
+
const offsetX = (elemRect.width - renderedWidth) / 2;
|
|
23487
|
+
const offsetY = (elemRect.height - renderedHeight) / 2;
|
|
23488
|
+
const imageX = relX - offsetX;
|
|
23489
|
+
const imageY = relY - offsetY;
|
|
23490
|
+
if (imageX < 0 || imageY < 0 || imageX > renderedWidth || imageY > renderedHeight) {
|
|
23491
|
+
return null;
|
|
23492
|
+
}
|
|
23493
|
+
return {
|
|
23494
|
+
x: imageX / scale,
|
|
23495
|
+
y: imageY / scale
|
|
23496
|
+
};
|
|
23497
|
+
}
|
|
23498
|
+
function normalizeWheelDelta(delta, deltaMode, viewportHeight) {
|
|
23499
|
+
let pixels;
|
|
23500
|
+
switch (deltaMode) {
|
|
23501
|
+
case 0:
|
|
23502
|
+
pixels = delta;
|
|
23503
|
+
break;
|
|
23504
|
+
case 1:
|
|
23505
|
+
pixels = delta * LINE_HEIGHT_PX;
|
|
23506
|
+
break;
|
|
23507
|
+
case 2:
|
|
23508
|
+
pixels = delta * (viewportHeight ?? 800);
|
|
23509
|
+
break;
|
|
23510
|
+
default:
|
|
23511
|
+
pixels = delta;
|
|
23512
|
+
}
|
|
23513
|
+
return Math.max(-MAX_DELTA, Math.min(MAX_DELTA, pixels));
|
|
23514
|
+
}
|
|
23515
|
+
function getModifiers(event) {
|
|
23516
|
+
let modifiers = 0;
|
|
23517
|
+
if (event.altKey) modifiers |= 1;
|
|
23518
|
+
if (event.ctrlKey) modifiers |= 2;
|
|
23519
|
+
if (event.metaKey) modifiers |= 4;
|
|
23520
|
+
if (event.shiftKey) modifiers |= 8;
|
|
23521
|
+
return modifiers;
|
|
23522
|
+
}
|
|
23523
|
+
|
|
23524
|
+
function isPrintableKey(key) {
|
|
23525
|
+
return key.length === 1;
|
|
23526
|
+
}
|
|
23527
|
+
|
|
23528
|
+
function useKeyboardInteraction(options) {
|
|
23529
|
+
const sendRef = React.useRef(options.sendMessage);
|
|
23530
|
+
const onEscapeRef = React.useRef(options.onEscape);
|
|
23531
|
+
React.useEffect(() => {
|
|
23532
|
+
sendRef.current = options.sendMessage;
|
|
23533
|
+
}, [options.sendMessage]);
|
|
23534
|
+
React.useEffect(() => {
|
|
23535
|
+
onEscapeRef.current = options.onEscape;
|
|
23536
|
+
}, [options.onEscape]);
|
|
23537
|
+
React.useEffect(() => {
|
|
23538
|
+
if (!options.enabled) {
|
|
23539
|
+
return;
|
|
23540
|
+
}
|
|
23541
|
+
function sendKeyboardMsg(eventType, key, code, text, modifiers) {
|
|
23542
|
+
const msg = { type: "keyboard", eventType };
|
|
23543
|
+
if (key !== void 0) msg.key = key;
|
|
23544
|
+
if (code !== void 0) msg.code = code;
|
|
23545
|
+
if (text !== void 0) msg.text = text;
|
|
23546
|
+
if (modifiers) msg.modifiers = modifiers;
|
|
23547
|
+
sendRef.current(JSON.stringify(msg));
|
|
23548
|
+
}
|
|
23549
|
+
function handleKeyDown(e) {
|
|
23550
|
+
if (e.isComposing || e.keyCode === 229) return;
|
|
23551
|
+
if (e.key === "Escape") {
|
|
23552
|
+
e.preventDefault();
|
|
23553
|
+
e.stopPropagation();
|
|
23554
|
+
onEscapeRef.current();
|
|
23555
|
+
return;
|
|
23556
|
+
}
|
|
23557
|
+
e.preventDefault();
|
|
23558
|
+
e.stopPropagation();
|
|
23559
|
+
const modifiers = getModifiers(e);
|
|
23560
|
+
const isPrintable = isPrintableKey(e.key);
|
|
23561
|
+
sendKeyboardMsg("keyDown", e.key, e.code, void 0, modifiers);
|
|
23562
|
+
if (isPrintable) {
|
|
23563
|
+
sendKeyboardMsg("char", e.key, void 0, e.key, modifiers);
|
|
23564
|
+
}
|
|
23565
|
+
}
|
|
23566
|
+
function handleKeyUp(e) {
|
|
23567
|
+
if (e.isComposing || e.keyCode === 229) return;
|
|
23568
|
+
if (e.key === "Escape") return;
|
|
23569
|
+
e.preventDefault();
|
|
23570
|
+
e.stopPropagation();
|
|
23571
|
+
sendKeyboardMsg("keyUp", e.key, e.code, void 0, getModifiers(e));
|
|
23572
|
+
}
|
|
23573
|
+
function handleCompositionEnd(e) {
|
|
23574
|
+
const text = e.data;
|
|
23575
|
+
if (!text) return;
|
|
23576
|
+
for (const char of text) {
|
|
23577
|
+
sendKeyboardMsg("keyDown", char, void 0, void 0, 0);
|
|
23578
|
+
sendKeyboardMsg("char", char, void 0, char, 0);
|
|
23579
|
+
sendKeyboardMsg("keyUp", char, void 0, void 0, 0);
|
|
23580
|
+
}
|
|
23581
|
+
}
|
|
23582
|
+
document.addEventListener("keydown", handleKeyDown, { capture: true });
|
|
23583
|
+
document.addEventListener("keyup", handleKeyUp, { capture: true });
|
|
23584
|
+
document.addEventListener("compositionend", handleCompositionEnd);
|
|
23585
|
+
return () => {
|
|
23586
|
+
document.removeEventListener("keydown", handleKeyDown, { capture: true });
|
|
23587
|
+
document.removeEventListener("keyup", handleKeyUp, { capture: true });
|
|
23588
|
+
document.removeEventListener("compositionend", handleCompositionEnd);
|
|
23589
|
+
};
|
|
23590
|
+
}, [options.enabled]);
|
|
23591
|
+
}
|
|
23592
|
+
|
|
23593
|
+
function useMouseInteraction(options) {
|
|
23594
|
+
const viewportRef = React.useRef(options.viewport);
|
|
23595
|
+
const sendRef = React.useRef(options.sendMessage);
|
|
23596
|
+
React.useEffect(() => {
|
|
23597
|
+
viewportRef.current = options.viewport;
|
|
23598
|
+
}, [options.viewport]);
|
|
23599
|
+
React.useEffect(() => {
|
|
23600
|
+
sendRef.current = options.sendMessage;
|
|
23601
|
+
}, [options.sendMessage]);
|
|
23602
|
+
React.useEffect(() => {
|
|
23603
|
+
if (!options.enabled || !options.imgRef.current) {
|
|
23604
|
+
return;
|
|
23605
|
+
}
|
|
23606
|
+
const imgElement = options.imgRef.current;
|
|
23607
|
+
function sendMouseEvent(eventType, x, y, button, clickCount, modifiers, deltaX, deltaY) {
|
|
23608
|
+
const msg = { type: "mouse", eventType, x, y };
|
|
23609
|
+
if (button !== void 0) msg.button = button;
|
|
23610
|
+
if (clickCount !== void 0) msg.clickCount = clickCount;
|
|
23611
|
+
if (modifiers !== void 0) msg.modifiers = modifiers;
|
|
23612
|
+
if (deltaX !== void 0) msg.deltaX = deltaX;
|
|
23613
|
+
if (deltaY !== void 0) msg.deltaY = deltaY;
|
|
23614
|
+
sendRef.current(JSON.stringify(msg));
|
|
23615
|
+
}
|
|
23616
|
+
function mapButton(domButton) {
|
|
23617
|
+
if (domButton === 2) return "right";
|
|
23618
|
+
if (domButton === 1) return "middle";
|
|
23619
|
+
return "left";
|
|
23620
|
+
}
|
|
23621
|
+
function handleMouseDown(e) {
|
|
23622
|
+
const viewport = viewportRef.current;
|
|
23623
|
+
if (!viewport) return;
|
|
23624
|
+
const rect = imgElement.getBoundingClientRect();
|
|
23625
|
+
const mapped = mapClientToViewport(e.clientX, e.clientY, rect, viewport);
|
|
23626
|
+
if (!mapped) return;
|
|
23627
|
+
const button = mapButton(e.button);
|
|
23628
|
+
const modifiers = getModifiers(e);
|
|
23629
|
+
sendMouseEvent("mouseMoved", mapped.x, mapped.y, void 0, void 0, modifiers);
|
|
23630
|
+
sendMouseEvent("mousePressed", mapped.x, mapped.y, button, 1, modifiers);
|
|
23631
|
+
}
|
|
23632
|
+
function handleMouseUp(e) {
|
|
23633
|
+
const viewport = viewportRef.current;
|
|
23634
|
+
if (!viewport) return;
|
|
23635
|
+
const rect = imgElement.getBoundingClientRect();
|
|
23636
|
+
const mapped = mapClientToViewport(e.clientX, e.clientY, rect, viewport);
|
|
23637
|
+
if (!mapped) return;
|
|
23638
|
+
const button = mapButton(e.button);
|
|
23639
|
+
sendMouseEvent("mouseReleased", mapped.x, mapped.y, button, 1, getModifiers(e));
|
|
23640
|
+
}
|
|
23641
|
+
function handleContextMenu(e) {
|
|
23642
|
+
e.preventDefault();
|
|
23643
|
+
}
|
|
23644
|
+
function handleWheel(e) {
|
|
23645
|
+
e.preventDefault();
|
|
23646
|
+
const viewport = viewportRef.current;
|
|
23647
|
+
if (!viewport) return;
|
|
23648
|
+
const rect = imgElement.getBoundingClientRect();
|
|
23649
|
+
const mapped = mapClientToViewport(e.clientX, e.clientY, rect, viewport);
|
|
23650
|
+
if (!mapped) return;
|
|
23651
|
+
const normDeltaX = normalizeWheelDelta(e.deltaX, e.deltaMode, viewport.height);
|
|
23652
|
+
const normDeltaY = normalizeWheelDelta(e.deltaY, e.deltaMode, viewport.height);
|
|
23653
|
+
sendMouseEvent("mouseWheel", mapped.x, mapped.y, void 0, void 0, getModifiers(e), normDeltaX, normDeltaY);
|
|
23654
|
+
}
|
|
23655
|
+
let rafId = null;
|
|
23656
|
+
let lastMoveTime = 0;
|
|
23657
|
+
let pendingMoveEvent = null;
|
|
23658
|
+
const FRAME_INTERVAL = 1e3 / 30;
|
|
23659
|
+
function handleMouseMove(e) {
|
|
23660
|
+
pendingMoveEvent = e;
|
|
23661
|
+
if (rafId !== null) return;
|
|
23662
|
+
rafId = requestAnimationFrame((now) => {
|
|
23663
|
+
rafId = null;
|
|
23664
|
+
if (!pendingMoveEvent) return;
|
|
23665
|
+
const delta = now - lastMoveTime;
|
|
23666
|
+
if (delta < FRAME_INTERVAL) return;
|
|
23667
|
+
lastMoveTime = now;
|
|
23668
|
+
const viewport = viewportRef.current;
|
|
23669
|
+
if (!viewport) {
|
|
23670
|
+
pendingMoveEvent = null;
|
|
23671
|
+
return;
|
|
23672
|
+
}
|
|
23673
|
+
const eventToProcess = pendingMoveEvent;
|
|
23674
|
+
pendingMoveEvent = null;
|
|
23675
|
+
const rect = imgElement.getBoundingClientRect();
|
|
23676
|
+
const mapped = mapClientToViewport(eventToProcess.clientX, eventToProcess.clientY, rect, viewport);
|
|
23677
|
+
if (!mapped) return;
|
|
23678
|
+
sendMouseEvent("mouseMoved", mapped.x, mapped.y, void 0, void 0, getModifiers(eventToProcess));
|
|
23679
|
+
});
|
|
23680
|
+
}
|
|
23681
|
+
imgElement.addEventListener("mousedown", handleMouseDown);
|
|
23682
|
+
imgElement.addEventListener("mouseup", handleMouseUp);
|
|
23683
|
+
imgElement.addEventListener("contextmenu", handleContextMenu);
|
|
23684
|
+
imgElement.addEventListener("wheel", handleWheel, { passive: false });
|
|
23685
|
+
imgElement.addEventListener("mousemove", handleMouseMove);
|
|
23686
|
+
return () => {
|
|
23687
|
+
imgElement.removeEventListener("mousedown", handleMouseDown);
|
|
23688
|
+
imgElement.removeEventListener("mouseup", handleMouseUp);
|
|
23689
|
+
imgElement.removeEventListener("contextmenu", handleContextMenu);
|
|
23690
|
+
imgElement.removeEventListener("wheel", handleWheel);
|
|
23691
|
+
imgElement.removeEventListener("mousemove", handleMouseMove);
|
|
23692
|
+
if (rafId !== null) {
|
|
23693
|
+
cancelAnimationFrame(rafId);
|
|
23694
|
+
}
|
|
23695
|
+
};
|
|
23696
|
+
}, [options.enabled, options.imgRef]);
|
|
23697
|
+
}
|
|
23698
|
+
|
|
23699
|
+
const TOOL_DISPLAY_NAMES = {
|
|
23700
|
+
// AgentBrowser tools
|
|
23701
|
+
browser_navigate: "Navigating",
|
|
23702
|
+
browser_goto: "Navigating",
|
|
23703
|
+
browser_click: "Clicking",
|
|
23704
|
+
browser_type: "Typing",
|
|
23705
|
+
browser_scroll: "Scrolling",
|
|
23706
|
+
browser_screenshot: "Capturing",
|
|
23707
|
+
browser_snapshot: "Reading page",
|
|
23708
|
+
browser_close: "Closing",
|
|
23709
|
+
browser_select: "Selecting",
|
|
23710
|
+
// StagehandBrowser tools
|
|
23711
|
+
stagehand_navigate: "Navigating",
|
|
23712
|
+
stagehand_act: "Acting",
|
|
23713
|
+
stagehand_extract: "Extracting",
|
|
23714
|
+
stagehand_observe: "Observing",
|
|
23715
|
+
stagehand_screenshot: "Capturing",
|
|
23716
|
+
stagehand_close: "Closing"
|
|
23717
|
+
};
|
|
23718
|
+
function AgentBusyOverlay({ toolName }) {
|
|
23719
|
+
const displayName = toolName ? TOOL_DISPLAY_NAMES[toolName] ?? toolName.replace(/^(browser_|stagehand_)/, "") : "Working";
|
|
23720
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-surface1/40 flex items-center justify-center z-10 cursor-not-allowed", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 bg-surface2 px-3 py-1.5 rounded-md border border-border1 shadow-sm", children: [
|
|
23721
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 text-accent1 animate-spin" }),
|
|
23722
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-medium text-neutral4", children: [
|
|
23723
|
+
"Agent: ",
|
|
23724
|
+
displayName
|
|
23725
|
+
] })
|
|
23726
|
+
] }) });
|
|
23727
|
+
}
|
|
23728
|
+
|
|
23729
|
+
const RIPPLE_SIZE = 32;
|
|
23730
|
+
const RIPPLE_RADIUS = RIPPLE_SIZE / 2;
|
|
23731
|
+
function ClickRippleOverlay({ ripples, onAnimationEnd }) {
|
|
23732
|
+
if (ripples.length === 0) return null;
|
|
23733
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: ripples.map((ripple) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
23734
|
+
"span",
|
|
23735
|
+
{
|
|
23736
|
+
className: "absolute rounded-full pointer-events-none animate-click-ripple bg-accent1/40",
|
|
23737
|
+
style: {
|
|
23738
|
+
left: ripple.x - RIPPLE_RADIUS,
|
|
23739
|
+
top: ripple.y - RIPPLE_RADIUS,
|
|
23740
|
+
width: RIPPLE_SIZE,
|
|
23741
|
+
height: RIPPLE_SIZE
|
|
23742
|
+
},
|
|
23743
|
+
onAnimationEnd: () => onAnimationEnd(ripple.id)
|
|
23744
|
+
},
|
|
23745
|
+
ripple.id
|
|
23746
|
+
)) });
|
|
23747
|
+
}
|
|
23748
|
+
|
|
23749
|
+
function BrowserViewFrame({ className, onStatusChange, onUrlChange, onFirstFrame }) {
|
|
23750
|
+
const imgRef = React.useRef(null);
|
|
23751
|
+
const containerRef = React.useRef(null);
|
|
23752
|
+
const hasFrameRef = React.useRef(false);
|
|
23753
|
+
const [hasFrame, setHasFrame] = React.useState(false);
|
|
23754
|
+
const [isInteractive, setIsInteractive] = React.useState(false);
|
|
23755
|
+
const { status, currentUrl, latestFrame, viewport, sendMessage } = useBrowserSession();
|
|
23756
|
+
React.useEffect(() => {
|
|
23757
|
+
if (latestFrame && imgRef.current) {
|
|
23758
|
+
imgRef.current.src = `data:image/jpeg;base64,${latestFrame}`;
|
|
23759
|
+
if (!hasFrameRef.current) {
|
|
23760
|
+
hasFrameRef.current = true;
|
|
23761
|
+
setHasFrame(true);
|
|
23762
|
+
}
|
|
23763
|
+
}
|
|
23764
|
+
}, [latestFrame]);
|
|
23765
|
+
const exitInteractive = React.useCallback(() => {
|
|
23766
|
+
setIsInteractive(false);
|
|
23767
|
+
}, []);
|
|
23768
|
+
const handleFrameClick = React.useCallback(() => {
|
|
23769
|
+
if (status === "streaming") {
|
|
23770
|
+
setIsInteractive(true);
|
|
23771
|
+
}
|
|
23772
|
+
}, [status]);
|
|
23773
|
+
const { isAgentBusy, activeToolName } = useInputCoordination();
|
|
23774
|
+
useMouseInteraction({
|
|
23775
|
+
imgRef,
|
|
23776
|
+
viewport,
|
|
23777
|
+
sendMessage,
|
|
23778
|
+
enabled: status === "streaming" && !isAgentBusy
|
|
23779
|
+
});
|
|
23780
|
+
useKeyboardInteraction({
|
|
23781
|
+
sendMessage,
|
|
23782
|
+
enabled: isInteractive && status === "streaming" && hasFrame && !isAgentBusy,
|
|
23783
|
+
onEscape: exitInteractive
|
|
23784
|
+
});
|
|
23785
|
+
const { ripples, removeRipple } = useClickRipple({
|
|
23786
|
+
imgRef,
|
|
23787
|
+
viewport,
|
|
23788
|
+
enabled: status === "streaming" && hasFrame && !isAgentBusy
|
|
23789
|
+
});
|
|
23790
|
+
React.useEffect(() => {
|
|
23791
|
+
onStatusChange?.(status);
|
|
23792
|
+
}, [status, onStatusChange]);
|
|
23793
|
+
React.useEffect(() => {
|
|
23794
|
+
onUrlChange?.(currentUrl);
|
|
23795
|
+
}, [currentUrl, onUrlChange]);
|
|
23796
|
+
React.useEffect(() => {
|
|
23797
|
+
if (hasFrame) {
|
|
23798
|
+
onFirstFrame?.();
|
|
23799
|
+
}
|
|
23800
|
+
}, [hasFrame, onFirstFrame]);
|
|
23801
|
+
React.useEffect(() => {
|
|
23802
|
+
if (!isInteractive) return;
|
|
23803
|
+
function handleDocumentMouseDown(e) {
|
|
23804
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
23805
|
+
setIsInteractive(false);
|
|
23806
|
+
}
|
|
23807
|
+
}
|
|
23808
|
+
function handleWindowBlur() {
|
|
23809
|
+
setIsInteractive(false);
|
|
23810
|
+
}
|
|
23811
|
+
document.addEventListener("mousedown", handleDocumentMouseDown);
|
|
23812
|
+
window.addEventListener("blur", handleWindowBlur);
|
|
23813
|
+
return () => {
|
|
23814
|
+
document.removeEventListener("mousedown", handleDocumentMouseDown);
|
|
23815
|
+
window.removeEventListener("blur", handleWindowBlur);
|
|
23816
|
+
};
|
|
23817
|
+
}, [isInteractive]);
|
|
23818
|
+
React.useEffect(() => {
|
|
23819
|
+
if (status !== "streaming") {
|
|
23820
|
+
setIsInteractive(false);
|
|
23821
|
+
}
|
|
23822
|
+
}, [status]);
|
|
23823
|
+
const isLoading = (status === "connecting" || status === "browser_starting" || status === "streaming") && !hasFrame;
|
|
23824
|
+
const isReconnecting = status === "disconnected" && hasFrame;
|
|
23825
|
+
const hasError = status === "error";
|
|
23826
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
23827
|
+
"div",
|
|
23828
|
+
{
|
|
23829
|
+
ref: containerRef,
|
|
23830
|
+
className: cn(
|
|
23831
|
+
"relative w-full aspect-video bg-surface2 rounded-md overflow-hidden",
|
|
23832
|
+
isInteractive && !isAgentBusy && "ring-2 ring-accent1",
|
|
23833
|
+
isInteractive && isAgentBusy && "ring-2 ring-amber-400",
|
|
23834
|
+
className
|
|
23835
|
+
),
|
|
23836
|
+
children: [
|
|
23837
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23838
|
+
"img",
|
|
23839
|
+
{
|
|
23840
|
+
ref: imgRef,
|
|
23841
|
+
alt: "Browser screencast",
|
|
23842
|
+
onClick: handleFrameClick,
|
|
23843
|
+
onKeyDown: (e) => {
|
|
23844
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
23845
|
+
e.preventDefault();
|
|
23846
|
+
handleFrameClick();
|
|
23847
|
+
}
|
|
23848
|
+
},
|
|
23849
|
+
tabIndex: status === "streaming" ? 0 : -1,
|
|
23850
|
+
role: "button",
|
|
23851
|
+
className: cn(
|
|
23852
|
+
"absolute inset-0 w-full h-full object-contain",
|
|
23853
|
+
hasFrame ? "opacity-100" : "opacity-0",
|
|
23854
|
+
status === "streaming" && (isInteractive ? "cursor-text" : "cursor-pointer")
|
|
23855
|
+
)
|
|
23856
|
+
}
|
|
23857
|
+
),
|
|
23858
|
+
/* @__PURE__ */ jsxRuntime.jsx(ClickRippleOverlay, { ripples, onAnimationEnd: removeRipple }),
|
|
23859
|
+
isAgentBusy && /* @__PURE__ */ jsxRuntime.jsx(AgentBusyOverlay, { toolName: activeToolName }),
|
|
23860
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsx(Skeleton, { className: "absolute inset-0" }),
|
|
23861
|
+
isReconnecting && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-surface1/80 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
|
|
23862
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-4 h-4 border-2 border-neutral4 border-t-transparent rounded-full animate-spin" }),
|
|
23863
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-neutral4", children: "Reconnecting..." })
|
|
23864
|
+
] }) }),
|
|
23865
|
+
hasError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-50 bg-black/70 backdrop-blur-sm flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3 px-6 py-4 text-center", children: [
|
|
23866
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-14 h-14 rounded-full bg-red-500/20 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
23867
|
+
"svg",
|
|
23868
|
+
{
|
|
23869
|
+
className: "w-7 h-7 text-red-400",
|
|
23870
|
+
fill: "none",
|
|
23871
|
+
viewBox: "0 0 24 24",
|
|
23872
|
+
stroke: "currentColor",
|
|
23873
|
+
strokeWidth: 1.5,
|
|
23874
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
23875
|
+
"path",
|
|
23876
|
+
{
|
|
23877
|
+
strokeLinecap: "round",
|
|
23878
|
+
strokeLinejoin: "round",
|
|
23879
|
+
d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
|
|
23880
|
+
}
|
|
23881
|
+
)
|
|
23882
|
+
}
|
|
23883
|
+
) }),
|
|
23884
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
23885
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-lg font-medium text-white", children: "Connection Error" }),
|
|
23886
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-white/70", children: "Failed to connect to browser" })
|
|
23887
|
+
] })
|
|
23888
|
+
] }) })
|
|
23889
|
+
]
|
|
23890
|
+
}
|
|
23891
|
+
);
|
|
23892
|
+
}
|
|
23893
|
+
|
|
23894
|
+
const statusBadgeVariants = cva(
|
|
23895
|
+
// Base styles
|
|
23896
|
+
"inline-flex items-center gap-1.5 rounded-full text-ui-xs font-medium transition-colors duration-normal",
|
|
23897
|
+
{
|
|
23898
|
+
variants: {
|
|
23899
|
+
variant: {
|
|
23900
|
+
success: "bg-accent1Dark text-accent1",
|
|
23901
|
+
warning: "bg-accent6Dark text-accent6",
|
|
23902
|
+
error: "bg-accent2Dark text-accent2",
|
|
23903
|
+
info: "bg-accent5Dark text-accent5",
|
|
23904
|
+
neutral: "bg-surface4 text-neutral4"
|
|
23905
|
+
},
|
|
23906
|
+
size: {
|
|
23907
|
+
sm: "px-1.5 py-0.5 text-ui-xs",
|
|
23908
|
+
md: "px-2 py-1 text-ui-xs",
|
|
23909
|
+
lg: "px-2.5 py-1 text-ui-sm"
|
|
23910
|
+
},
|
|
23911
|
+
withDot: {
|
|
23912
|
+
true: "",
|
|
23913
|
+
false: ""
|
|
23914
|
+
},
|
|
23915
|
+
pulse: {
|
|
23916
|
+
true: "",
|
|
23917
|
+
false: ""
|
|
23918
|
+
}
|
|
23919
|
+
},
|
|
23920
|
+
defaultVariants: {
|
|
23921
|
+
variant: "neutral",
|
|
23922
|
+
size: "md",
|
|
23923
|
+
withDot: false,
|
|
23924
|
+
pulse: false
|
|
23925
|
+
}
|
|
23926
|
+
}
|
|
23927
|
+
);
|
|
23928
|
+
const dotVariants = cva("rounded-full", {
|
|
23929
|
+
variants: {
|
|
23930
|
+
variant: {
|
|
23931
|
+
success: "bg-accent1",
|
|
23932
|
+
warning: "bg-accent6",
|
|
23933
|
+
error: "bg-accent2",
|
|
23934
|
+
info: "bg-accent5",
|
|
23935
|
+
neutral: "bg-neutral3"
|
|
23936
|
+
},
|
|
23937
|
+
size: {
|
|
23938
|
+
sm: "w-1 h-1",
|
|
23939
|
+
md: "w-1.5 h-1.5",
|
|
23940
|
+
lg: "w-2 h-2"
|
|
23941
|
+
},
|
|
23942
|
+
pulse: {
|
|
23943
|
+
true: "animate-pulse",
|
|
23944
|
+
false: ""
|
|
23945
|
+
}
|
|
23946
|
+
},
|
|
23947
|
+
defaultVariants: {
|
|
23948
|
+
variant: "neutral",
|
|
23949
|
+
size: "md",
|
|
23950
|
+
pulse: false
|
|
23951
|
+
}
|
|
23952
|
+
});
|
|
23953
|
+
function StatusBadge({ className, variant, size, withDot, pulse, children, ...props }) {
|
|
23954
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(statusBadgeVariants({ variant, size, withDot, pulse }), className), ...props, children: [
|
|
23955
|
+
withDot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: dotVariants({ variant, size, pulse }) }),
|
|
23956
|
+
children
|
|
23957
|
+
] });
|
|
23958
|
+
}
|
|
23959
|
+
|
|
23960
|
+
function getStatusBadgeConfig$2(status) {
|
|
23961
|
+
switch (status) {
|
|
23962
|
+
case "idle":
|
|
23963
|
+
return { variant: "neutral", pulse: false, label: "Idle" };
|
|
23964
|
+
case "connecting":
|
|
23965
|
+
return { variant: "warning", pulse: true, label: "Connecting" };
|
|
23966
|
+
case "connected":
|
|
23967
|
+
return { variant: "warning", pulse: true, label: "Connected" };
|
|
23968
|
+
case "browser_starting":
|
|
23969
|
+
return { variant: "warning", pulse: true, label: "Starting" };
|
|
23970
|
+
case "streaming":
|
|
23971
|
+
return { variant: "success", pulse: false, label: "Live" };
|
|
23972
|
+
case "browser_closed":
|
|
23973
|
+
return { variant: "neutral", pulse: false, label: "Closed" };
|
|
23974
|
+
case "disconnected":
|
|
23975
|
+
return { variant: "error", pulse: true, label: "Disconnected" };
|
|
23976
|
+
case "error":
|
|
23977
|
+
return { variant: "error", pulse: false, label: "Error" };
|
|
23978
|
+
default:
|
|
23979
|
+
return { variant: "neutral", pulse: false, label: "Unknown" };
|
|
23980
|
+
}
|
|
23981
|
+
}
|
|
23982
|
+
function BrowserSidebarTab() {
|
|
23983
|
+
const { status, currentUrl, closeBrowser, setViewMode } = useBrowserSession();
|
|
23984
|
+
const handleClose = React.useCallback(async () => {
|
|
23985
|
+
await closeBrowser();
|
|
23986
|
+
}, [closeBrowser]);
|
|
23987
|
+
const handleCenterView = React.useCallback(() => {
|
|
23988
|
+
setViewMode("modal");
|
|
23989
|
+
}, [setViewMode]);
|
|
23990
|
+
const handleMinimize = React.useCallback(() => {
|
|
23991
|
+
setViewMode("collapsed");
|
|
23992
|
+
}, [setViewMode]);
|
|
23993
|
+
const handleFirstFrame = React.useCallback(() => {
|
|
23994
|
+
}, []);
|
|
23995
|
+
const statusConfig = getStatusBadgeConfig$2(status);
|
|
23996
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
23997
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 border-b border-border1 shrink-0", children: [
|
|
23998
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-4 w-4 text-neutral4 shrink-0" }),
|
|
23999
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 px-2 py-1 bg-surface2 rounded border border-border1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-xs truncate block", currentUrl ? "text-neutral5" : "text-neutral3 italic"), children: currentUrl || "No URL" }) }),
|
|
24000
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { variant: statusConfig.variant, size: "sm", withDot: true, pulse: statusConfig.pulse, children: statusConfig.label })
|
|
24001
|
+
] }),
|
|
24002
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
24003
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
24004
|
+
/* @__PURE__ */ jsxRuntime.jsx(BrowserViewFrame, { className: "w-full", onFirstFrame: handleFirstFrame }),
|
|
24005
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 right-2 flex gap-1", children: [
|
|
24006
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24007
|
+
IconButton,
|
|
24008
|
+
{
|
|
24009
|
+
variant: "light",
|
|
24010
|
+
size: "sm",
|
|
24011
|
+
tooltip: "Center view",
|
|
24012
|
+
onClick: handleCenterView,
|
|
24013
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
24014
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-3.5 w-3.5" })
|
|
24015
|
+
}
|
|
24016
|
+
),
|
|
24017
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24018
|
+
IconButton,
|
|
24019
|
+
{
|
|
24020
|
+
variant: "light",
|
|
24021
|
+
size: "sm",
|
|
24022
|
+
tooltip: "Minimize to chat",
|
|
24023
|
+
onClick: handleMinimize,
|
|
24024
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
24025
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize2, { className: "h-3.5 w-3.5" })
|
|
24026
|
+
}
|
|
24027
|
+
),
|
|
24028
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24029
|
+
IconButton,
|
|
24030
|
+
{
|
|
24031
|
+
variant: "light",
|
|
24032
|
+
size: "sm",
|
|
24033
|
+
tooltip: "Close browser",
|
|
24034
|
+
onClick: handleClose,
|
|
24035
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
24036
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
24037
|
+
}
|
|
24038
|
+
)
|
|
24039
|
+
] })
|
|
24040
|
+
] }) }),
|
|
24041
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(BrowserToolCallHistory, {}) })
|
|
24042
|
+
] })
|
|
24043
|
+
] });
|
|
24044
|
+
}
|
|
24045
|
+
|
|
22930
24046
|
const AgentMemoryConfig = ({ agentId }) => {
|
|
22931
24047
|
const { data, isLoading } = useMemoryConfig(agentId);
|
|
22932
24048
|
const [expandedSections, setExpandedSections] = React.useState(/* @__PURE__ */ new Set(["General", "Semantic Recall"]));
|
|
@@ -24034,6 +25150,7 @@ function AgentMemory({ agentId, threadId, memoryType }) {
|
|
|
24034
25150
|
function AgentInformation({ agentId, threadId }) {
|
|
24035
25151
|
const { data: agent } = useAgent(agentId);
|
|
24036
25152
|
const { data: memory, isLoading: isMemoryLoading } = useMemory(agentId);
|
|
25153
|
+
const { hasSession, isInSidebar } = useBrowserSession();
|
|
24037
25154
|
const hasMemory = !isMemoryLoading && Boolean(memory?.result);
|
|
24038
25155
|
const { selectedTab, handleTabChange } = useAgentInformationTab({
|
|
24039
25156
|
isMemoryLoading,
|
|
@@ -24041,39 +25158,46 @@ function AgentInformation({ agentId, threadId }) {
|
|
|
24041
25158
|
});
|
|
24042
25159
|
return /* @__PURE__ */ jsxRuntime.jsxs(AgentInformationLayout, { children: [
|
|
24043
25160
|
/* @__PURE__ */ jsxRuntime.jsx(AgentEntityHeader, { agentId }),
|
|
24044
|
-
/* @__PURE__ */ jsxRuntime.
|
|
24045
|
-
/* @__PURE__ */ jsxRuntime.
|
|
24046
|
-
|
|
24047
|
-
/* @__PURE__ */ jsxRuntime.
|
|
24048
|
-
|
|
24049
|
-
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
24054
|
-
|
|
24055
|
-
|
|
24056
|
-
|
|
24057
|
-
|
|
25161
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-hidden border-t border-border1 flex flex-col relative", children: [
|
|
25162
|
+
hasSession && isInSidebar && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-10 bg-surface1", children: /* @__PURE__ */ jsxRuntime.jsx(BrowserSidebarTab, {}) }),
|
|
25163
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tabs, { defaultTab: "overview", value: selectedTab, onValueChange: handleTabChange, children: [
|
|
25164
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
|
|
25165
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "overview", children: "Overview" }),
|
|
25166
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "model-settings", children: "Model Settings" }),
|
|
25167
|
+
hasMemory && /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "memory", children: "Memory" }),
|
|
25168
|
+
agent?.requestContextSchema && /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "request-context", children: "Request Context" }),
|
|
25169
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "tracing-options", children: "Tracing Options" })
|
|
25170
|
+
] }),
|
|
25171
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "overview", children: /* @__PURE__ */ jsxRuntime.jsx(AgentMetadata, { agentId }) }),
|
|
25172
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "model-settings", children: /* @__PURE__ */ jsxRuntime.jsx(AgentSettings, { agentId }) }),
|
|
25173
|
+
agent?.requestContextSchema && /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "request-context", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-5", children: /* @__PURE__ */ jsxRuntime.jsx(RequestContextSchemaForm, { requestContextSchema: agent.requestContextSchema }) }) }),
|
|
25174
|
+
hasMemory && /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "memory", children: /* @__PURE__ */ jsxRuntime.jsx(AgentMemory, { agentId, threadId, memoryType: memory?.memoryType }) }),
|
|
25175
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "tracing-options", children: /* @__PURE__ */ jsxRuntime.jsx(TracingRunOptions, {}) })
|
|
25176
|
+
] })
|
|
25177
|
+
] })
|
|
24058
25178
|
] });
|
|
24059
25179
|
}
|
|
24060
25180
|
const STORAGE_KEY = "agent-info-selected-tab";
|
|
25181
|
+
const VALID_TABS = /* @__PURE__ */ new Set(["overview", "model-settings", "memory", "request-context", "tracing-options"]);
|
|
24061
25182
|
const useAgentInformationTab = ({ isMemoryLoading, hasMemory }) => {
|
|
24062
25183
|
const [selectedTab, setSelectedTab] = React.useState(() => {
|
|
24063
|
-
|
|
25184
|
+
const stored = sessionStorage.getItem(STORAGE_KEY) || "overview";
|
|
25185
|
+
if (!VALID_TABS.has(stored)) return "overview";
|
|
25186
|
+
return stored;
|
|
24064
25187
|
});
|
|
24065
|
-
const
|
|
25188
|
+
const effectiveTab = (() => {
|
|
25189
|
+
if (!VALID_TABS.has(selectedTab)) return "overview";
|
|
25190
|
+
if (selectedTab === "memory" && !isMemoryLoading && !hasMemory) {
|
|
25191
|
+
return "overview";
|
|
25192
|
+
}
|
|
25193
|
+
return selectedTab;
|
|
25194
|
+
})();
|
|
25195
|
+
const handleTabChange = React.useCallback((value) => {
|
|
24066
25196
|
setSelectedTab(value);
|
|
24067
25197
|
sessionStorage.setItem(STORAGE_KEY, value);
|
|
24068
|
-
};
|
|
24069
|
-
React.useEffect(() => {
|
|
24070
|
-
if (!isMemoryLoading && !hasMemory && selectedTab === "memory") {
|
|
24071
|
-
setSelectedTab("overview");
|
|
24072
|
-
sessionStorage.setItem(STORAGE_KEY, "overview");
|
|
24073
|
-
}
|
|
24074
|
-
}, [isMemoryLoading, hasMemory, selectedTab]);
|
|
25198
|
+
}, []);
|
|
24075
25199
|
return {
|
|
24076
|
-
selectedTab,
|
|
25200
|
+
selectedTab: effectiveTab,
|
|
24077
25201
|
handleTabChange
|
|
24078
25202
|
};
|
|
24079
25203
|
};
|
|
@@ -24090,9 +25214,9 @@ const AgentInformationTabLayout = ({ children, agentId }) => {
|
|
|
24090
25214
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden border-t border-border1 flex flex-col min-w-0 w-full", children: /* @__PURE__ */ jsxRuntime.jsx(Tabs, { defaultTab: "overview", value: selectedTab, onValueChange: handleTabChange, children }) });
|
|
24091
25215
|
};
|
|
24092
25216
|
|
|
24093
|
-
const AgentLayout = ({ agentId, children, leftSlot, rightSlot }) => {
|
|
25217
|
+
const AgentLayout = ({ agentId, children, leftSlot, rightSlot, browserOverlay }) => {
|
|
24094
25218
|
const { defaultLayout, onLayoutChange } = reactResizablePanels.useDefaultLayout({
|
|
24095
|
-
id: `agent-layout-${agentId}`,
|
|
25219
|
+
id: `agent-layout-v2-${agentId}`,
|
|
24096
25220
|
storage: localStorage
|
|
24097
25221
|
});
|
|
24098
25222
|
const computedClassName = getMainContentContentClassName({
|
|
@@ -24100,42 +25224,545 @@ const AgentLayout = ({ agentId, children, leftSlot, rightSlot }) => {
|
|
|
24100
25224
|
isDivided: true,
|
|
24101
25225
|
hasLeftServiceColumn: Boolean(leftSlot)
|
|
24102
25226
|
});
|
|
24103
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
24104
|
-
|
|
24105
|
-
/* @__PURE__ */ jsxRuntime.
|
|
24106
|
-
|
|
24107
|
-
|
|
24108
|
-
|
|
24109
|
-
|
|
24110
|
-
|
|
24111
|
-
|
|
24112
|
-
|
|
24113
|
-
|
|
24114
|
-
|
|
24115
|
-
|
|
24116
|
-
|
|
24117
|
-
|
|
24118
|
-
|
|
25227
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-full w-full overflow-hidden", children: [
|
|
25228
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactResizablePanels.Group, { className: computedClassName, defaultLayout, onLayoutChange, children: [
|
|
25229
|
+
leftSlot && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
25230
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25231
|
+
CollapsiblePanel,
|
|
25232
|
+
{
|
|
25233
|
+
direction: "left",
|
|
25234
|
+
id: "left-slot",
|
|
25235
|
+
minSize: 200,
|
|
25236
|
+
maxSize: "30%",
|
|
25237
|
+
defaultSize: 200,
|
|
25238
|
+
collapsedSize: 60,
|
|
25239
|
+
collapsible: true,
|
|
25240
|
+
children: leftSlot
|
|
25241
|
+
}
|
|
25242
|
+
),
|
|
25243
|
+
/* @__PURE__ */ jsxRuntime.jsx(PanelSeparator, {})
|
|
25244
|
+
] }),
|
|
25245
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactResizablePanels.Panel, { id: "main-slot", className: "grid overflow-y-auto relative bg-surface1 py-4", children }),
|
|
25246
|
+
rightSlot && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
25247
|
+
/* @__PURE__ */ jsxRuntime.jsx(PanelSeparator, {}),
|
|
25248
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25249
|
+
CollapsiblePanel,
|
|
25250
|
+
{
|
|
25251
|
+
direction: "right",
|
|
25252
|
+
id: "right-slot",
|
|
25253
|
+
minSize: 300,
|
|
25254
|
+
maxSize: "50%",
|
|
25255
|
+
defaultSize: "30%",
|
|
25256
|
+
collapsedSize: 60,
|
|
25257
|
+
collapsible: true,
|
|
25258
|
+
children: rightSlot
|
|
25259
|
+
}
|
|
25260
|
+
)
|
|
25261
|
+
] })
|
|
24119
25262
|
] }),
|
|
24120
|
-
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24124
|
-
|
|
25263
|
+
browserOverlay
|
|
25264
|
+
] });
|
|
25265
|
+
};
|
|
25266
|
+
|
|
25267
|
+
function BrowserThumbnail({ agentName = "Agent" }) {
|
|
25268
|
+
const { hasSession, viewMode, status, currentUrl, latestFrame, setViewMode, closeBrowser } = useBrowserSession();
|
|
25269
|
+
const { toolCalls } = useBrowserToolCalls();
|
|
25270
|
+
const imgRef = React.useRef(null);
|
|
25271
|
+
const [hasFrame, setHasFrame] = React.useState(false);
|
|
25272
|
+
const actionsRef = React.useRef(null);
|
|
25273
|
+
const isExpanded = viewMode === "expanded";
|
|
25274
|
+
React.useEffect(() => {
|
|
25275
|
+
if (latestFrame) {
|
|
25276
|
+
const frameData = `data:image/jpeg;base64,${latestFrame}`;
|
|
25277
|
+
if (imgRef.current) {
|
|
25278
|
+
imgRef.current.src = frameData;
|
|
25279
|
+
}
|
|
25280
|
+
if (!hasFrame) {
|
|
25281
|
+
setHasFrame(true);
|
|
25282
|
+
}
|
|
25283
|
+
}
|
|
25284
|
+
}, [latestFrame, hasFrame]);
|
|
25285
|
+
React.useEffect(() => {
|
|
25286
|
+
if (!hasSession) {
|
|
25287
|
+
setHasFrame(false);
|
|
25288
|
+
if (imgRef.current) {
|
|
25289
|
+
imgRef.current.src = "";
|
|
25290
|
+
}
|
|
25291
|
+
}
|
|
25292
|
+
}, [hasSession]);
|
|
25293
|
+
React.useEffect(() => {
|
|
25294
|
+
if (isExpanded && actionsRef.current) {
|
|
25295
|
+
actionsRef.current.scrollTop = actionsRef.current.scrollHeight;
|
|
25296
|
+
}
|
|
25297
|
+
}, [toolCalls.length, isExpanded]);
|
|
25298
|
+
const handleToggleExpand = React.useCallback(() => {
|
|
25299
|
+
setViewMode(isExpanded ? "collapsed" : "expanded");
|
|
25300
|
+
}, [isExpanded, setViewMode]);
|
|
25301
|
+
const handleOpenModal = React.useCallback(() => {
|
|
25302
|
+
setViewMode("modal");
|
|
25303
|
+
}, [setViewMode]);
|
|
25304
|
+
const handleOpenSidebar = React.useCallback(() => {
|
|
25305
|
+
setViewMode("sidebar");
|
|
25306
|
+
}, [setViewMode]);
|
|
25307
|
+
const handleClose = React.useCallback(async () => {
|
|
25308
|
+
await closeBrowser();
|
|
25309
|
+
}, [closeBrowser]);
|
|
25310
|
+
const displayUrl = React.useMemo(() => {
|
|
25311
|
+
if (!currentUrl) return "Browser";
|
|
25312
|
+
try {
|
|
25313
|
+
return new URL(currentUrl).hostname;
|
|
25314
|
+
} catch {
|
|
25315
|
+
return currentUrl;
|
|
25316
|
+
}
|
|
25317
|
+
}, [currentUrl]);
|
|
25318
|
+
if (!hasSession || viewMode === "modal" || viewMode === "sidebar") {
|
|
25319
|
+
return null;
|
|
25320
|
+
}
|
|
25321
|
+
const isLive = status === "streaming";
|
|
25322
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25323
|
+
"div",
|
|
25324
|
+
{
|
|
25325
|
+
className: cn(
|
|
25326
|
+
"bg-surface2 border border-border1 rounded-lg overflow-hidden transition-all duration-200",
|
|
25327
|
+
"hover:border-border2"
|
|
25328
|
+
),
|
|
25329
|
+
children: [
|
|
25330
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
25331
|
+
"button",
|
|
25332
|
+
{
|
|
25333
|
+
type: "button",
|
|
25334
|
+
onClick: handleToggleExpand,
|
|
25335
|
+
className: cn(
|
|
25336
|
+
"group flex items-center gap-3 w-full px-4 py-3",
|
|
25337
|
+
"hover:bg-surface3 transition-colors",
|
|
25338
|
+
"focus:outline-none focus:ring-2 focus:ring-accent1 focus:ring-inset"
|
|
25339
|
+
),
|
|
25340
|
+
children: [
|
|
25341
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative shrink-0 w-24 h-14 bg-surface3 rounded-md overflow-hidden border border-border1", children: [
|
|
25342
|
+
hasFrame ? /* @__PURE__ */ jsxRuntime.jsx("img", { ref: imgRef, alt: "Browser preview", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-full h-full", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Monitor, { className: "h-5 w-5 text-neutral3" }) }),
|
|
25343
|
+
isLive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1 right-1 w-2 h-2 bg-success rounded-full animate-pulse" })
|
|
25344
|
+
] }),
|
|
25345
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 text-left", children: [
|
|
25346
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
25347
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm font-medium text-neutral6 truncate", children: [
|
|
25348
|
+
agentName,
|
|
25349
|
+
"'s browser"
|
|
25350
|
+
] }),
|
|
25351
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { variant: isLive ? "success" : "neutral", size: "sm", withDot: true, pulse: isLive, children: isLive ? "Live" : "Idle" })
|
|
25352
|
+
] }),
|
|
25353
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-neutral4 truncate mt-0.5", children: displayUrl })
|
|
25354
|
+
] }),
|
|
25355
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 text-neutral4 group-hover:text-neutral5 transition-colors", children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-5 w-5" }) })
|
|
25356
|
+
]
|
|
25357
|
+
}
|
|
25358
|
+
),
|
|
25359
|
+
isExpanded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border1", children: [
|
|
25360
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
25361
|
+
/* @__PURE__ */ jsxRuntime.jsx(BrowserViewFrame, { className: "w-full" }),
|
|
25362
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 right-2 flex gap-1", children: [
|
|
25363
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25364
|
+
IconButton,
|
|
25365
|
+
{
|
|
25366
|
+
variant: "light",
|
|
25367
|
+
size: "sm",
|
|
25368
|
+
tooltip: "Center view",
|
|
25369
|
+
onClick: handleOpenModal,
|
|
25370
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
25371
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "h-3.5 w-3.5" })
|
|
25372
|
+
}
|
|
25373
|
+
),
|
|
25374
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25375
|
+
IconButton,
|
|
25376
|
+
{
|
|
25377
|
+
variant: "light",
|
|
25378
|
+
size: "sm",
|
|
25379
|
+
tooltip: "Open in sidebar",
|
|
25380
|
+
onClick: handleOpenSidebar,
|
|
25381
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
25382
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRight, { className: "h-3.5 w-3.5" })
|
|
25383
|
+
}
|
|
25384
|
+
),
|
|
25385
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25386
|
+
IconButton,
|
|
25387
|
+
{
|
|
25388
|
+
variant: "light",
|
|
25389
|
+
size: "sm",
|
|
25390
|
+
tooltip: "Close browser",
|
|
25391
|
+
onClick: handleClose,
|
|
25392
|
+
className: "bg-surface1/80 backdrop-blur-sm",
|
|
25393
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" })
|
|
25394
|
+
}
|
|
25395
|
+
)
|
|
25396
|
+
] })
|
|
25397
|
+
] }) }),
|
|
25398
|
+
toolCalls.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { ref: actionsRef, className: "border-t border-border1 max-h-40 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-2", children: [
|
|
25399
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-xs font-medium text-neutral4 mb-2", children: "Browser Actions" }),
|
|
25400
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: toolCalls.slice(-5).map((entry) => /* @__PURE__ */ jsxRuntime.jsx(BrowserToolCallItem, { entry }, entry.toolCallId)) })
|
|
25401
|
+
] }) })
|
|
25402
|
+
] })
|
|
25403
|
+
]
|
|
25404
|
+
}
|
|
25405
|
+
);
|
|
25406
|
+
}
|
|
25407
|
+
|
|
25408
|
+
function getStatusBadgeConfig$1(status) {
|
|
25409
|
+
switch (status) {
|
|
25410
|
+
case "idle":
|
|
25411
|
+
return { variant: "neutral", pulse: false, label: "Idle" };
|
|
25412
|
+
case "connecting":
|
|
25413
|
+
return { variant: "warning", pulse: true, label: "Connecting" };
|
|
25414
|
+
case "connected":
|
|
25415
|
+
return { variant: "warning", pulse: true, label: "Connected" };
|
|
25416
|
+
case "browser_starting":
|
|
25417
|
+
return { variant: "warning", pulse: true, label: "Starting" };
|
|
25418
|
+
case "streaming":
|
|
25419
|
+
return { variant: "success", pulse: false, label: "Live" };
|
|
25420
|
+
case "browser_closed":
|
|
25421
|
+
return { variant: "neutral", pulse: false, label: "Closed" };
|
|
25422
|
+
case "disconnected":
|
|
25423
|
+
return { variant: "error", pulse: true, label: "Disconnected" };
|
|
25424
|
+
case "error":
|
|
25425
|
+
return { variant: "error", pulse: false, label: "Error" };
|
|
25426
|
+
default:
|
|
25427
|
+
return { variant: "neutral", pulse: false, label: "Unknown" };
|
|
25428
|
+
}
|
|
25429
|
+
}
|
|
25430
|
+
function BrowserViewHeader({
|
|
25431
|
+
url,
|
|
25432
|
+
status,
|
|
25433
|
+
isCollapsed,
|
|
25434
|
+
className,
|
|
25435
|
+
onClose,
|
|
25436
|
+
onToggleCollapse,
|
|
25437
|
+
onTuck
|
|
25438
|
+
}) {
|
|
25439
|
+
const { variant, pulse, label } = getStatusBadgeConfig$1(status);
|
|
25440
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25441
|
+
"div",
|
|
25442
|
+
{
|
|
25443
|
+
className: cn(
|
|
25444
|
+
"flex items-center justify-between px-3 py-2 border-b border-border1 bg-surface1",
|
|
25445
|
+
isCollapsed ? "rounded-md" : "rounded-t-md",
|
|
25446
|
+
className
|
|
25447
|
+
),
|
|
25448
|
+
children: [
|
|
25449
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 mr-3", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm text-neutral4 truncate block", !url && "text-neutral3 italic"), children: url || "No URL" }) }),
|
|
25450
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
25451
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { variant, size: "sm", withDot: true, pulse, children: label }),
|
|
25452
|
+
onTuck && /* @__PURE__ */ jsxRuntime.jsx(
|
|
25453
|
+
"button",
|
|
25454
|
+
{
|
|
25455
|
+
onClick: onTuck,
|
|
25456
|
+
className: "p-1 rounded hover:bg-surface3 text-neutral3 hover:text-neutral6 transition-colors",
|
|
25457
|
+
title: "Minimize to pill",
|
|
25458
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minus, { className: "h-4 w-4" })
|
|
25459
|
+
}
|
|
25460
|
+
),
|
|
25461
|
+
onToggleCollapse && /* @__PURE__ */ jsxRuntime.jsx(
|
|
25462
|
+
"button",
|
|
25463
|
+
{
|
|
25464
|
+
onClick: onToggleCollapse,
|
|
25465
|
+
className: "p-1 rounded hover:bg-surface3 text-neutral3 hover:text-neutral6 transition-colors",
|
|
25466
|
+
title: isCollapsed ? "Expand browser view" : "Minimize browser view",
|
|
25467
|
+
children: isCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4" })
|
|
25468
|
+
}
|
|
25469
|
+
),
|
|
25470
|
+
onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
25471
|
+
"button",
|
|
25472
|
+
{
|
|
25473
|
+
onClick: onClose,
|
|
25474
|
+
className: "p-1 rounded hover:bg-surface3 text-neutral3 hover:text-neutral6 transition-colors",
|
|
25475
|
+
title: "Close browser session",
|
|
25476
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
|
|
25477
|
+
}
|
|
25478
|
+
)
|
|
25479
|
+
] })
|
|
25480
|
+
]
|
|
25481
|
+
}
|
|
25482
|
+
);
|
|
25483
|
+
}
|
|
25484
|
+
|
|
25485
|
+
function getStatusBadgeConfig(status) {
|
|
25486
|
+
switch (status) {
|
|
25487
|
+
case "idle":
|
|
25488
|
+
return { variant: "neutral", pulse: false, label: "Idle" };
|
|
25489
|
+
case "connecting":
|
|
25490
|
+
return { variant: "warning", pulse: true, label: "Connecting" };
|
|
25491
|
+
case "connected":
|
|
25492
|
+
return { variant: "warning", pulse: true, label: "Connected" };
|
|
25493
|
+
case "browser_starting":
|
|
25494
|
+
return { variant: "warning", pulse: true, label: "Starting" };
|
|
25495
|
+
case "streaming":
|
|
25496
|
+
return { variant: "success", pulse: false, label: "Live" };
|
|
25497
|
+
case "browser_closed":
|
|
25498
|
+
return { variant: "neutral", pulse: false, label: "Closed" };
|
|
25499
|
+
case "disconnected":
|
|
25500
|
+
return { variant: "error", pulse: true, label: "Disconnected" };
|
|
25501
|
+
case "error":
|
|
25502
|
+
return { variant: "error", pulse: false, label: "Error" };
|
|
25503
|
+
default:
|
|
25504
|
+
return { variant: "neutral", pulse: false, label: "Unknown" };
|
|
25505
|
+
}
|
|
25506
|
+
}
|
|
25507
|
+
function BrowserViewPanel() {
|
|
25508
|
+
const { viewMode, status, currentUrl, hide, closeBrowser, setViewMode } = useBrowserSession();
|
|
25509
|
+
const [isVisible, setIsVisible] = React.useState(false);
|
|
25510
|
+
const dialogRef = React.useRef(null);
|
|
25511
|
+
const previousFocusRef = React.useRef(null);
|
|
25512
|
+
const isPanelOpen = viewMode === "modal";
|
|
25513
|
+
React.useEffect(() => {
|
|
25514
|
+
if (isPanelOpen) {
|
|
25515
|
+
requestAnimationFrame(() => setIsVisible(true));
|
|
25516
|
+
} else {
|
|
25517
|
+
setIsVisible(false);
|
|
25518
|
+
}
|
|
25519
|
+
}, [isPanelOpen]);
|
|
25520
|
+
React.useEffect(() => {
|
|
25521
|
+
if (isPanelOpen) {
|
|
25522
|
+
previousFocusRef.current = document.activeElement;
|
|
25523
|
+
dialogRef.current?.focus();
|
|
25524
|
+
} else if (previousFocusRef.current) {
|
|
25525
|
+
previousFocusRef.current.focus();
|
|
25526
|
+
previousFocusRef.current = null;
|
|
25527
|
+
}
|
|
25528
|
+
}, [isPanelOpen]);
|
|
25529
|
+
const handleClose = React.useCallback(async () => {
|
|
25530
|
+
await closeBrowser();
|
|
25531
|
+
}, [closeBrowser]);
|
|
25532
|
+
const handleMinimize = React.useCallback(() => {
|
|
25533
|
+
hide();
|
|
25534
|
+
}, [hide]);
|
|
25535
|
+
const handleOpenSidebar = React.useCallback(() => {
|
|
25536
|
+
setViewMode("sidebar");
|
|
25537
|
+
}, [setViewMode]);
|
|
25538
|
+
const handleOpenExternal = React.useCallback(() => {
|
|
25539
|
+
if (!currentUrl) return;
|
|
25540
|
+
try {
|
|
25541
|
+
const url = new URL(currentUrl);
|
|
25542
|
+
if (url.protocol === "http:" || url.protocol === "https:") {
|
|
25543
|
+
window.open(url.href, "_blank", "noopener,noreferrer");
|
|
25544
|
+
}
|
|
25545
|
+
} catch {
|
|
25546
|
+
}
|
|
25547
|
+
}, [currentUrl]);
|
|
25548
|
+
React.useEffect(() => {
|
|
25549
|
+
if (!isPanelOpen) return;
|
|
25550
|
+
const handleKeyDown = (e) => {
|
|
25551
|
+
if (e.key === "Escape") {
|
|
25552
|
+
e.preventDefault();
|
|
25553
|
+
hide();
|
|
25554
|
+
}
|
|
25555
|
+
};
|
|
25556
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
25557
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
25558
|
+
}, [isPanelOpen, hide]);
|
|
25559
|
+
const handleBackdropClick = React.useCallback(
|
|
25560
|
+
(e) => {
|
|
25561
|
+
if (e.target === e.currentTarget) {
|
|
25562
|
+
hide();
|
|
25563
|
+
}
|
|
25564
|
+
},
|
|
25565
|
+
[hide]
|
|
25566
|
+
);
|
|
25567
|
+
const statusConfig = getStatusBadgeConfig(status);
|
|
25568
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
25569
|
+
"div",
|
|
25570
|
+
{
|
|
25571
|
+
className: cn(
|
|
25572
|
+
"fixed inset-0 z-50 flex items-center justify-center p-8",
|
|
25573
|
+
"bg-black/60 backdrop-blur-sm transition-opacity duration-200",
|
|
25574
|
+
isPanelOpen && isVisible ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
25575
|
+
),
|
|
25576
|
+
onClick: handleBackdropClick,
|
|
25577
|
+
"aria-hidden": !isPanelOpen,
|
|
25578
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
25579
|
+
"div",
|
|
24125
25580
|
{
|
|
24126
|
-
|
|
24127
|
-
|
|
24128
|
-
|
|
24129
|
-
|
|
24130
|
-
|
|
24131
|
-
|
|
24132
|
-
|
|
24133
|
-
|
|
25581
|
+
ref: dialogRef,
|
|
25582
|
+
role: "dialog",
|
|
25583
|
+
"aria-modal": "true",
|
|
25584
|
+
"aria-label": "Browser view",
|
|
25585
|
+
tabIndex: -1,
|
|
25586
|
+
className: cn(
|
|
25587
|
+
"flex flex-col w-full max-w-5xl max-h-full",
|
|
25588
|
+
"bg-surface2 rounded-xl border border-border1 shadow-2xl overflow-hidden",
|
|
25589
|
+
"transition-transform duration-200 outline-none",
|
|
25590
|
+
isPanelOpen && isVisible ? "scale-100" : "scale-95"
|
|
25591
|
+
),
|
|
25592
|
+
onClick: (e) => e.stopPropagation(),
|
|
25593
|
+
children: [
|
|
25594
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-border1 shrink-0", children: [
|
|
25595
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Globe, { className: "h-4 w-4 text-neutral4 shrink-0" }),
|
|
25596
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 px-3 py-1.5 bg-surface3 rounded-md border border-border1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm truncate block", currentUrl ? "text-neutral5" : "text-neutral3 italic"), children: currentUrl || "No URL" }) }),
|
|
25597
|
+
/* @__PURE__ */ jsxRuntime.jsx(StatusBadge, { variant: statusConfig.variant, size: "sm", withDot: true, pulse: statusConfig.pulse, children: statusConfig.label }),
|
|
25598
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-2", children: [
|
|
25599
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton, { variant: "ghost", size: "sm", tooltip: "Open in sidebar", onClick: handleOpenSidebar, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRight, { className: "h-4 w-4" }) }),
|
|
25600
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton, { variant: "ghost", size: "sm", tooltip: "Minimize to chat", onClick: handleMinimize, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize2, { className: "h-4 w-4" }) }),
|
|
25601
|
+
currentUrl && /* @__PURE__ */ jsxRuntime.jsx(IconButton, { variant: "ghost", size: "sm", tooltip: "Open in new tab", onClick: handleOpenExternal, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4" }) }),
|
|
25602
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton, { variant: "ghost", size: "sm", tooltip: "Close browser", onClick: handleClose, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })
|
|
25603
|
+
] })
|
|
25604
|
+
] }),
|
|
25605
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
25606
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx(BrowserViewFrame, { className: "w-full max-h-[60vh]" }) }),
|
|
25607
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 pb-4", children: /* @__PURE__ */ jsxRuntime.jsx(BrowserToolCallHistory, {}) })
|
|
25608
|
+
] })
|
|
25609
|
+
]
|
|
24134
25610
|
}
|
|
24135
25611
|
)
|
|
24136
|
-
|
|
24137
|
-
|
|
24138
|
-
}
|
|
25612
|
+
}
|
|
25613
|
+
);
|
|
25614
|
+
}
|
|
25615
|
+
|
|
25616
|
+
function useBrowserStream(options) {
|
|
25617
|
+
const { agentId, threadId, enabled = true, onFrame, maxReconnectAttempts = 5 } = options;
|
|
25618
|
+
const [status, setStatus] = React.useState("idle");
|
|
25619
|
+
const [error, setError] = React.useState(null);
|
|
25620
|
+
const [currentUrl, setCurrentUrl] = React.useState(null);
|
|
25621
|
+
const [viewport, setViewport] = React.useState(null);
|
|
25622
|
+
const wsRef = React.useRef(null);
|
|
25623
|
+
const reconnectAttemptRef = React.useRef(0);
|
|
25624
|
+
const reconnectTimeoutRef = React.useRef(null);
|
|
25625
|
+
const onFrameRef = React.useRef(onFrame);
|
|
25626
|
+
React.useEffect(() => {
|
|
25627
|
+
onFrameRef.current = onFrame;
|
|
25628
|
+
}, [onFrame]);
|
|
25629
|
+
const clearReconnectTimeout = React.useCallback(() => {
|
|
25630
|
+
if (reconnectTimeoutRef.current) {
|
|
25631
|
+
clearTimeout(reconnectTimeoutRef.current);
|
|
25632
|
+
reconnectTimeoutRef.current = null;
|
|
25633
|
+
}
|
|
25634
|
+
}, []);
|
|
25635
|
+
const disconnect = React.useCallback(() => {
|
|
25636
|
+
clearReconnectTimeout();
|
|
25637
|
+
if (wsRef.current) {
|
|
25638
|
+
wsRef.current.close();
|
|
25639
|
+
wsRef.current = null;
|
|
25640
|
+
}
|
|
25641
|
+
setStatus("idle");
|
|
25642
|
+
setError(null);
|
|
25643
|
+
setViewport(null);
|
|
25644
|
+
}, [clearReconnectTimeout]);
|
|
25645
|
+
const sendMessage = React.useCallback((data) => {
|
|
25646
|
+
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
25647
|
+
wsRef.current.send(data);
|
|
25648
|
+
}
|
|
25649
|
+
}, []);
|
|
25650
|
+
const connect = React.useCallback(() => {
|
|
25651
|
+
clearReconnectTimeout();
|
|
25652
|
+
if (wsRef.current) {
|
|
25653
|
+
wsRef.current.close();
|
|
25654
|
+
wsRef.current = null;
|
|
25655
|
+
}
|
|
25656
|
+
setStatus("connecting");
|
|
25657
|
+
setError(null);
|
|
25658
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
25659
|
+
const wsUrl = `${protocol}//${window.location.host}/browser/${agentId}/stream?threadId=${encodeURIComponent(threadId)}`;
|
|
25660
|
+
try {
|
|
25661
|
+
const ws = new WebSocket(wsUrl);
|
|
25662
|
+
wsRef.current = ws;
|
|
25663
|
+
ws.onopen = () => {
|
|
25664
|
+
setStatus("connected");
|
|
25665
|
+
setError(null);
|
|
25666
|
+
reconnectAttemptRef.current = 0;
|
|
25667
|
+
};
|
|
25668
|
+
ws.onmessage = (event) => {
|
|
25669
|
+
const data = event.data;
|
|
25670
|
+
if (data.startsWith("{")) {
|
|
25671
|
+
try {
|
|
25672
|
+
const parsed = JSON.parse(data);
|
|
25673
|
+
if (parsed.status) {
|
|
25674
|
+
switch (parsed.status) {
|
|
25675
|
+
case "browser_starting":
|
|
25676
|
+
setStatus("browser_starting");
|
|
25677
|
+
break;
|
|
25678
|
+
case "streaming":
|
|
25679
|
+
setStatus("streaming");
|
|
25680
|
+
break;
|
|
25681
|
+
case "browser_closed":
|
|
25682
|
+
setStatus("browser_closed");
|
|
25683
|
+
break;
|
|
25684
|
+
case "stopped":
|
|
25685
|
+
setStatus("disconnected");
|
|
25686
|
+
break;
|
|
25687
|
+
default:
|
|
25688
|
+
break;
|
|
25689
|
+
}
|
|
25690
|
+
}
|
|
25691
|
+
if (parsed.error) {
|
|
25692
|
+
setError(parsed.error);
|
|
25693
|
+
setStatus("error");
|
|
25694
|
+
}
|
|
25695
|
+
if (parsed.url) {
|
|
25696
|
+
setCurrentUrl(parsed.url);
|
|
25697
|
+
}
|
|
25698
|
+
if (parsed.viewport) {
|
|
25699
|
+
setViewport(parsed.viewport);
|
|
25700
|
+
}
|
|
25701
|
+
} catch {
|
|
25702
|
+
onFrameRef.current?.(data);
|
|
25703
|
+
}
|
|
25704
|
+
} else {
|
|
25705
|
+
onFrameRef.current?.(data);
|
|
25706
|
+
setStatus((prev) => prev !== "streaming" ? "streaming" : prev);
|
|
25707
|
+
}
|
|
25708
|
+
};
|
|
25709
|
+
ws.onerror = () => {
|
|
25710
|
+
setError("WebSocket error occurred");
|
|
25711
|
+
};
|
|
25712
|
+
ws.onclose = (event) => {
|
|
25713
|
+
wsRef.current = null;
|
|
25714
|
+
if (!event.wasClean && enabled && reconnectAttemptRef.current < maxReconnectAttempts) {
|
|
25715
|
+
setStatus("disconnected");
|
|
25716
|
+
const delay = Math.min(1e3 * Math.pow(2, reconnectAttemptRef.current), 3e4);
|
|
25717
|
+
reconnectAttemptRef.current += 1;
|
|
25718
|
+
reconnectTimeoutRef.current = setTimeout(() => {
|
|
25719
|
+
connect();
|
|
25720
|
+
}, delay);
|
|
25721
|
+
} else if (reconnectAttemptRef.current >= maxReconnectAttempts) {
|
|
25722
|
+
setStatus("error");
|
|
25723
|
+
setError("Maximum reconnection attempts reached");
|
|
25724
|
+
} else {
|
|
25725
|
+
setStatus("idle");
|
|
25726
|
+
}
|
|
25727
|
+
};
|
|
25728
|
+
} catch (err) {
|
|
25729
|
+
setStatus("error");
|
|
25730
|
+
setError(err instanceof Error ? err.message : "Failed to create WebSocket");
|
|
25731
|
+
}
|
|
25732
|
+
}, [agentId, threadId, enabled, maxReconnectAttempts, clearReconnectTimeout]);
|
|
25733
|
+
React.useEffect(() => {
|
|
25734
|
+
const handleVisibilityChange = () => {
|
|
25735
|
+
if (document.visibilityState === "visible" && enabled && status === "disconnected") {
|
|
25736
|
+
reconnectAttemptRef.current = 0;
|
|
25737
|
+
connect();
|
|
25738
|
+
}
|
|
25739
|
+
};
|
|
25740
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
25741
|
+
return () => {
|
|
25742
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
25743
|
+
};
|
|
25744
|
+
}, [enabled, status, connect]);
|
|
25745
|
+
React.useEffect(() => {
|
|
25746
|
+
return () => {
|
|
25747
|
+
clearReconnectTimeout();
|
|
25748
|
+
if (wsRef.current) {
|
|
25749
|
+
wsRef.current.close();
|
|
25750
|
+
wsRef.current = null;
|
|
25751
|
+
}
|
|
25752
|
+
};
|
|
25753
|
+
}, [clearReconnectTimeout]);
|
|
25754
|
+
const isActive = status === "connecting" || status === "connected" || status === "browser_starting" || status === "streaming";
|
|
25755
|
+
return {
|
|
25756
|
+
status,
|
|
25757
|
+
error,
|
|
25758
|
+
currentUrl,
|
|
25759
|
+
viewport,
|
|
25760
|
+
sendMessage,
|
|
25761
|
+
connect,
|
|
25762
|
+
disconnect,
|
|
25763
|
+
isActive
|
|
25764
|
+
};
|
|
25765
|
+
}
|
|
24139
25766
|
|
|
24140
25767
|
const ruleSchema = zod.z.object({
|
|
24141
25768
|
field: zod.z.string(),
|
|
@@ -33780,11 +35407,36 @@ function getInitialInput(traceDetails) {
|
|
|
33780
35407
|
return JSON.stringify(rawInput, null, 2);
|
|
33781
35408
|
}
|
|
33782
35409
|
function TraceAsItemDialog({ traceDetails, traceId, isOpen, onClose, level = 2 }) {
|
|
35410
|
+
const client = react.useMastraClient();
|
|
35411
|
+
const { data: trajectory, isLoading: isTrajectoryLoading } = reactQuery.useQuery({
|
|
35412
|
+
queryKey: ["trace-trajectory", traceId],
|
|
35413
|
+
queryFn: () => client.getTraceTrajectory(traceId),
|
|
35414
|
+
enabled: isOpen && !!traceId
|
|
35415
|
+
});
|
|
35416
|
+
const initialTrajectory = trajectory?.steps && trajectory.steps.length > 0 ? JSON.stringify(
|
|
35417
|
+
{
|
|
35418
|
+
steps: trajectory.steps.map((step) => {
|
|
35419
|
+
const { name, stepType, children, ...rest } = step;
|
|
35420
|
+
const expected = { name, stepType };
|
|
35421
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
35422
|
+
if (v != null && k !== "durationMs" && k !== "metadata") {
|
|
35423
|
+
expected[k] = v;
|
|
35424
|
+
}
|
|
35425
|
+
}
|
|
35426
|
+
return expected;
|
|
35427
|
+
}),
|
|
35428
|
+
ordering: "relaxed"
|
|
35429
|
+
},
|
|
35430
|
+
null,
|
|
35431
|
+
2
|
|
35432
|
+
) : void 0;
|
|
33783
35433
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33784
35434
|
SaveAsDatasetItemDialog,
|
|
33785
35435
|
{
|
|
33786
35436
|
initialInput: getInitialInput(traceDetails),
|
|
33787
35437
|
initialGroundTruth: traceDetails?.output != null ? JSON.stringify(traceDetails.output, null, 2) : "",
|
|
35438
|
+
initialTrajectory,
|
|
35439
|
+
trajectoryLoading: isTrajectoryLoading,
|
|
33788
35440
|
breadcrumb: /* @__PURE__ */ jsxRuntime.jsxs(TextAndIcon, { children: [
|
|
33789
35441
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeIcon, {}),
|
|
33790
35442
|
" ",
|
|
@@ -34486,7 +36138,10 @@ function TraceDialog({
|
|
|
34486
36138
|
if (initialSpanId) {
|
|
34487
36139
|
setSelectedSpanId(initialSpanId);
|
|
34488
36140
|
setDialogIsOpen(true);
|
|
36141
|
+
return;
|
|
34489
36142
|
}
|
|
36143
|
+
setSelectedSpanId(void 0);
|
|
36144
|
+
setDialogIsOpen(false);
|
|
34490
36145
|
}, [initialSpanId]);
|
|
34491
36146
|
React.useEffect(() => {
|
|
34492
36147
|
if (spanScoresPage > 0) {
|
|
@@ -34517,11 +36172,17 @@ function TraceDialog({
|
|
|
34517
36172
|
});
|
|
34518
36173
|
const handleSpanClick = (id) => {
|
|
34519
36174
|
if (selectedSpanId === id) {
|
|
36175
|
+
if (traceId) {
|
|
36176
|
+
navigate(computeTraceLink(traceId));
|
|
36177
|
+
}
|
|
34520
36178
|
setSelectedSpanId(void 0);
|
|
34521
|
-
|
|
34522
|
-
|
|
34523
|
-
|
|
34524
|
-
|
|
36179
|
+
return;
|
|
36180
|
+
}
|
|
36181
|
+
setSelectedSpanId(id);
|
|
36182
|
+
setSpanDialogDefaultTab("details");
|
|
36183
|
+
setDialogIsOpen(true);
|
|
36184
|
+
if (traceId) {
|
|
36185
|
+
navigate(computeTraceLink(traceId, id));
|
|
34525
36186
|
}
|
|
34526
36187
|
};
|
|
34527
36188
|
const handleToScoring = () => {
|
|
@@ -34771,6 +36432,70 @@ function TraceDialog({
|
|
|
34771
36432
|
] });
|
|
34772
36433
|
}
|
|
34773
36434
|
|
|
36435
|
+
const sizeClasses = {
|
|
36436
|
+
small: "text-[11px] pt-[5px] pb-[4px]",
|
|
36437
|
+
default: "text-[12px] pt-[5px] pb-[4px] ",
|
|
36438
|
+
large: "text-[13px] pt-[5px] pb-[4px] "
|
|
36439
|
+
};
|
|
36440
|
+
const bgColorClasses = {
|
|
36441
|
+
gray: { bright: "bg-neutral-700", muted: "bg-neutral-700/80" },
|
|
36442
|
+
red: { bright: "bg-red-900", muted: "bg-red-900/80" },
|
|
36443
|
+
orange: { bright: "bg-yellow-900", muted: "bg-yellow-900/80" },
|
|
36444
|
+
blue: { bright: "bg-blue-800", muted: "bg-blue-800/80" },
|
|
36445
|
+
green: { bright: "bg-green-900", muted: "bg-green-900/80" },
|
|
36446
|
+
purple: { bright: "bg-purple-900", muted: "bg-purple-900/80" },
|
|
36447
|
+
yellow: { bright: "bg-yellow-700", muted: "bg-yellow-700/80" },
|
|
36448
|
+
cyan: { bright: "bg-cyan-900", muted: "bg-cyan-900/80" },
|
|
36449
|
+
pink: { bright: "bg-pink-900", muted: "bg-pink-900/80" }
|
|
36450
|
+
};
|
|
36451
|
+
const txtIntensityClasses = {
|
|
36452
|
+
bright: "text-neutral4",
|
|
36453
|
+
muted: "text-neutral3"
|
|
36454
|
+
};
|
|
36455
|
+
const Chip = ({
|
|
36456
|
+
color = "gray",
|
|
36457
|
+
size = "default",
|
|
36458
|
+
intensity = "bright",
|
|
36459
|
+
className,
|
|
36460
|
+
children,
|
|
36461
|
+
...props
|
|
36462
|
+
}) => {
|
|
36463
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36464
|
+
"span",
|
|
36465
|
+
{
|
|
36466
|
+
className: cn(
|
|
36467
|
+
"inline-flex items-center rounded-md uppercase px-[0.5em] gap-[0.4em] tracking-wide font-normal",
|
|
36468
|
+
// general styles for svg icons within the chip
|
|
36469
|
+
"[&>svg]:w-[1em] [&>svg]:h-[1em] [&>svg]:translate-y-[-0.02em] [&>svg]:mx-[-0.2em]",
|
|
36470
|
+
// if the chip has only one child and it's an svg, make it fully opaque
|
|
36471
|
+
"[&>svg]:opacity-50 [&>svg:first-child:last-child]:opacity-100",
|
|
36472
|
+
sizeClasses[size],
|
|
36473
|
+
bgColorClasses[color][intensity],
|
|
36474
|
+
txtIntensityClasses[intensity],
|
|
36475
|
+
className
|
|
36476
|
+
),
|
|
36477
|
+
style: { lineHeight: 1 },
|
|
36478
|
+
...props,
|
|
36479
|
+
children
|
|
36480
|
+
}
|
|
36481
|
+
);
|
|
36482
|
+
};
|
|
36483
|
+
|
|
36484
|
+
const ChipsGroup = React.forwardRef(function ChipsGroup2({ children, className, ...props }, ref) {
|
|
36485
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
36486
|
+
"div",
|
|
36487
|
+
{
|
|
36488
|
+
ref,
|
|
36489
|
+
className: cn(
|
|
36490
|
+
"flex gap-[1px] items-center [&>*:not(:last-child)]:rounded-r-none [&>*:not(:first-child)]:rounded-l-none",
|
|
36491
|
+
className
|
|
36492
|
+
),
|
|
36493
|
+
...props,
|
|
36494
|
+
children
|
|
36495
|
+
}
|
|
36496
|
+
);
|
|
36497
|
+
});
|
|
36498
|
+
|
|
34774
36499
|
function formatTimestamp$2(dateStr) {
|
|
34775
36500
|
const date = new Date(dateStr);
|
|
34776
36501
|
return date.toLocaleDateString(void 0, {
|
|
@@ -34836,6 +36561,43 @@ function parseOutput(output) {
|
|
|
34836
36561
|
error: typeof obj.error === "string" ? obj.error : obj.error ? String(obj.error) : void 0
|
|
34837
36562
|
};
|
|
34838
36563
|
}
|
|
36564
|
+
function TrajectoryStepsSection({ traceId }) {
|
|
36565
|
+
const client = react.useMastraClient();
|
|
36566
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
36567
|
+
const {
|
|
36568
|
+
data: trajectory,
|
|
36569
|
+
isLoading,
|
|
36570
|
+
isError
|
|
36571
|
+
} = reactQuery.useQuery({
|
|
36572
|
+
queryKey: ["trajectory", traceId],
|
|
36573
|
+
queryFn: () => client.getTraceTrajectory(traceId),
|
|
36574
|
+
enabled: isOpen
|
|
36575
|
+
});
|
|
36576
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: [
|
|
36577
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 text-xs text-purple-400 font-medium hover:text-purple-300", children: [
|
|
36578
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3 w-3 shrink-0" }),
|
|
36579
|
+
"Trajectory Steps"
|
|
36580
|
+
] }),
|
|
36581
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mt-1 px-3 py-2", children: [
|
|
36582
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { className: "h-3 w-3" }),
|
|
36583
|
+
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3", children: "Loading trajectory..." })
|
|
36584
|
+
] }) : isError ? /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-red-400 mt-1 px-3 py-2", children: "Failed to load trajectory steps" }) : trajectory?.steps && trajectory.steps.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 space-y-1", children: [
|
|
36585
|
+
trajectory.steps.map((step, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-1.5 bg-surface1 rounded text-xs", children: [
|
|
36586
|
+
/* @__PURE__ */ jsxRuntime.jsx(Chip, { size: "small", color: "purple", children: String(step.stepType || "step") }),
|
|
36587
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral5 font-mono font-medium", children: String(step.name || `Step ${i + 1}`) }),
|
|
36588
|
+
typeof step.durationMs === "number" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-neutral2 ml-auto", children: [
|
|
36589
|
+
step.durationMs,
|
|
36590
|
+
"ms"
|
|
36591
|
+
] })
|
|
36592
|
+
] }, i)),
|
|
36593
|
+
typeof trajectory.totalDurationMs === "number" && /* @__PURE__ */ jsxRuntime.jsxs(Txt, { variant: "ui-xs", className: "text-neutral3 px-3 py-1", children: [
|
|
36594
|
+
"Total: ",
|
|
36595
|
+
trajectory.totalDurationMs,
|
|
36596
|
+
"ms"
|
|
36597
|
+
] })
|
|
36598
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral2 mt-1 px-3 py-2", children: "No trajectory steps found" }) })
|
|
36599
|
+
] });
|
|
36600
|
+
}
|
|
34839
36601
|
function ResultOutputSection({
|
|
34840
36602
|
output,
|
|
34841
36603
|
traceId,
|
|
@@ -35072,12 +36834,31 @@ function ExperimentResultsPanel({
|
|
|
35072
36834
|
/* @__PURE__ */ jsxRuntime.jsx(Checkbox, { checked: isChecked, onCheckedChange: () => toggleItem(result.id) }),
|
|
35073
36835
|
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: hasError ? "error" : "success", children: hasError ? "Error" : "Success" }),
|
|
35074
36836
|
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral2 font-mono", children: result.itemId.slice(0, 8) }),
|
|
35075
|
-
itemScores.length > 0 && /* @__PURE__ */ jsxRuntime.
|
|
35076
|
-
s.
|
|
35077
|
-
|
|
35078
|
-
|
|
35079
|
-
|
|
36837
|
+
itemScores.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-auto flex-wrap", children: [
|
|
36838
|
+
itemScores.filter((s) => s.entityType !== "TRAJECTORY").map((s) => /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant: "default", children: [
|
|
36839
|
+
s.scorerId,
|
|
36840
|
+
": ",
|
|
36841
|
+
s.score.toFixed(3)
|
|
36842
|
+
] }, s.scorerId)),
|
|
36843
|
+
itemScores.filter((s) => s.entityType === "TRAJECTORY").map((s) => /* @__PURE__ */ jsxRuntime.jsxs(Chip, { size: "small", color: "purple", children: [
|
|
36844
|
+
s.scorerId,
|
|
36845
|
+
": ",
|
|
36846
|
+
s.score.toFixed(3)
|
|
36847
|
+
] }, s.scorerId))
|
|
36848
|
+
] })
|
|
35080
36849
|
] }),
|
|
36850
|
+
itemScores.some((s) => s.entityType === "TRAJECTORY") && /* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { children: [
|
|
36851
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 text-xs text-purple-400 font-medium hover:text-purple-300", children: [
|
|
36852
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3 w-3 shrink-0" }),
|
|
36853
|
+
"Trajectory Score Details"
|
|
36854
|
+
] }),
|
|
36855
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleContent, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 space-y-2", children: itemScores.filter((s) => s.entityType === "TRAJECTORY").map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface1 rounded px-3 py-2 space-y-1", children: [
|
|
36856
|
+
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-purple-400 font-medium", children: s.scorerId }),
|
|
36857
|
+
s.reason && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-neutral4", children: s.reason }),
|
|
36858
|
+
s.preprocessStepResult && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-neutral3 overflow-x-auto whitespace-pre-wrap break-words max-h-48 overflow-y-auto", children: JSON.stringify(s.preprocessStepResult, null, 2) })
|
|
36859
|
+
] }, s.scorerId)) }) })
|
|
36860
|
+
] }),
|
|
36861
|
+
result.traceId && itemScores.some((s) => s.entityType === "TRAJECTORY") && /* @__PURE__ */ jsxRuntime.jsx(TrajectoryStepsSection, { traceId: result.traceId }),
|
|
35081
36862
|
/* @__PURE__ */ jsxRuntime.jsxs(Collapsible, { children: [
|
|
35082
36863
|
/* @__PURE__ */ jsxRuntime.jsxs(CollapsibleTrigger, { className: "flex items-center gap-1.5 text-xs text-neutral3 font-medium hover:text-neutral5", children: [
|
|
35083
36864
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3 w-3 shrink-0" }),
|
|
@@ -35341,70 +37122,6 @@ const useDatasetVersions = (datasetId) => {
|
|
|
35341
37122
|
});
|
|
35342
37123
|
};
|
|
35343
37124
|
|
|
35344
|
-
const sizeClasses = {
|
|
35345
|
-
small: "text-[11px] pt-[5px] pb-[4px]",
|
|
35346
|
-
default: "text-[12px] pt-[5px] pb-[4px] ",
|
|
35347
|
-
large: "text-[13px] pt-[5px] pb-[4px] "
|
|
35348
|
-
};
|
|
35349
|
-
const bgColorClasses = {
|
|
35350
|
-
gray: { bright: "bg-neutral-700", muted: "bg-neutral-700/80" },
|
|
35351
|
-
red: { bright: "bg-red-900", muted: "bg-red-900/80" },
|
|
35352
|
-
orange: { bright: "bg-yellow-900", muted: "bg-yellow-900/80" },
|
|
35353
|
-
blue: { bright: "bg-blue-800", muted: "bg-blue-800/80" },
|
|
35354
|
-
green: { bright: "bg-green-900", muted: "bg-green-900/80" },
|
|
35355
|
-
purple: { bright: "bg-purple-900", muted: "bg-purple-900/80" },
|
|
35356
|
-
yellow: { bright: "bg-yellow-700", muted: "bg-yellow-700/80" },
|
|
35357
|
-
cyan: { bright: "bg-cyan-900", muted: "bg-cyan-900/80" },
|
|
35358
|
-
pink: { bright: "bg-pink-900", muted: "bg-pink-900/80" }
|
|
35359
|
-
};
|
|
35360
|
-
const txtIntensityClasses = {
|
|
35361
|
-
bright: "text-neutral4",
|
|
35362
|
-
muted: "text-neutral3"
|
|
35363
|
-
};
|
|
35364
|
-
const Chip = ({
|
|
35365
|
-
color = "gray",
|
|
35366
|
-
size = "default",
|
|
35367
|
-
intensity = "bright",
|
|
35368
|
-
className,
|
|
35369
|
-
children,
|
|
35370
|
-
...props
|
|
35371
|
-
}) => {
|
|
35372
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
35373
|
-
"span",
|
|
35374
|
-
{
|
|
35375
|
-
className: cn(
|
|
35376
|
-
"inline-flex items-center rounded-md uppercase px-[0.5em] gap-[0.4em] tracking-wide font-normal",
|
|
35377
|
-
// general styles for svg icons within the chip
|
|
35378
|
-
"[&>svg]:w-[1em] [&>svg]:h-[1em] [&>svg]:translate-y-[-0.02em] [&>svg]:mx-[-0.2em]",
|
|
35379
|
-
// if the chip has only one child and it's an svg, make it fully opaque
|
|
35380
|
-
"[&>svg]:opacity-50 [&>svg:first-child:last-child]:opacity-100",
|
|
35381
|
-
sizeClasses[size],
|
|
35382
|
-
bgColorClasses[color][intensity],
|
|
35383
|
-
txtIntensityClasses[intensity],
|
|
35384
|
-
className
|
|
35385
|
-
),
|
|
35386
|
-
style: { lineHeight: 1 },
|
|
35387
|
-
...props,
|
|
35388
|
-
children
|
|
35389
|
-
}
|
|
35390
|
-
);
|
|
35391
|
-
};
|
|
35392
|
-
|
|
35393
|
-
const ChipsGroup = React.forwardRef(function ChipsGroup2({ children, className, ...props }, ref) {
|
|
35394
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
35395
|
-
"div",
|
|
35396
|
-
{
|
|
35397
|
-
ref,
|
|
35398
|
-
className: cn(
|
|
35399
|
-
"flex gap-[1px] items-center [&>*:not(:last-child)]:rounded-r-none [&>*:not(:first-child)]:rounded-l-none",
|
|
35400
|
-
className
|
|
35401
|
-
),
|
|
35402
|
-
...props,
|
|
35403
|
-
children
|
|
35404
|
-
}
|
|
35405
|
-
);
|
|
35406
|
-
});
|
|
35407
|
-
|
|
35408
37125
|
function formatTimestamp$1(date) {
|
|
35409
37126
|
const d = new Date(date);
|
|
35410
37127
|
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" }) + ", " + d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" });
|
|
@@ -35415,6 +37132,11 @@ function truncateValue$2(value, maxLength = 120) {
|
|
|
35415
37132
|
if (!str || str.length <= maxLength) return str || "-";
|
|
35416
37133
|
return str.slice(0, maxLength) + "…";
|
|
35417
37134
|
}
|
|
37135
|
+
function getExpectedTrajectoryLabel(expectedTrajectory) {
|
|
37136
|
+
const traj = expectedTrajectory;
|
|
37137
|
+
const steps = Array.isArray(traj?.steps) ? traj.steps.length : 0;
|
|
37138
|
+
return steps > 0 ? `${steps} expected steps` : "trajectory";
|
|
37139
|
+
}
|
|
35418
37140
|
const TAG_COLORS = ["blue", "green", "purple", "orange", "cyan", "pink", "red", "yellow"];
|
|
35419
37141
|
function getTagColor(tag) {
|
|
35420
37142
|
let hash = 0;
|
|
@@ -35698,7 +37420,10 @@ function DatasetDetailView({
|
|
|
35698
37420
|
className: "w-full text-left px-4 py-2 hover:bg-surface3 transition-colors flex items-start gap-2",
|
|
35699
37421
|
children: [
|
|
35700
37422
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "sm", className: "text-neutral3 mt-0.5 shrink-0", children: isExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, {}) }),
|
|
35701
|
-
/* @__PURE__ */ jsxRuntime.
|
|
37423
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [
|
|
37424
|
+
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral5 block truncate flex-1", children: truncateValue$2(item.input) }),
|
|
37425
|
+
item.expectedTrajectory != null && /* @__PURE__ */ jsxRuntime.jsx(Chip, { size: "small", color: "purple", children: getExpectedTrajectoryLabel(item.expectedTrajectory) })
|
|
37426
|
+
] })
|
|
35702
37427
|
]
|
|
35703
37428
|
}
|
|
35704
37429
|
),
|
|
@@ -35820,12 +37545,14 @@ function ExpandedItemEditor({
|
|
|
35820
37545
|
const [isConfirmingDelete, setIsConfirmingDelete] = React.useState(false);
|
|
35821
37546
|
const [inputValue, setInputValue] = React.useState("");
|
|
35822
37547
|
const [groundTruthValue, setGroundTruthValue] = React.useState("");
|
|
37548
|
+
const [trajectoryValue, setTrajectoryValue] = React.useState("");
|
|
35823
37549
|
const { updateItem, deleteItem } = useDatasetMutations();
|
|
35824
37550
|
const startEditing = React.useCallback(() => {
|
|
35825
37551
|
setInputValue(formatValue$4(item.input));
|
|
35826
37552
|
setGroundTruthValue(formatValue$4(item.groundTruth));
|
|
37553
|
+
setTrajectoryValue(formatValue$4(item.expectedTrajectory));
|
|
35827
37554
|
setIsEditing(true);
|
|
35828
|
-
}, [item.input, item.groundTruth]);
|
|
37555
|
+
}, [item.input, item.groundTruth, item.expectedTrajectory]);
|
|
35829
37556
|
const cancelEditing = React.useCallback(() => {
|
|
35830
37557
|
setIsEditing(false);
|
|
35831
37558
|
}, []);
|
|
@@ -35852,19 +37579,28 @@ function ExpandedItemEditor({
|
|
|
35852
37579
|
parsedGroundTruth = groundTruthValue;
|
|
35853
37580
|
}
|
|
35854
37581
|
}
|
|
37582
|
+
let parsedTrajectory;
|
|
37583
|
+
if (trajectoryValue.trim()) {
|
|
37584
|
+
try {
|
|
37585
|
+
parsedTrajectory = JSON.parse(trajectoryValue);
|
|
37586
|
+
} catch {
|
|
37587
|
+
parsedTrajectory = trajectoryValue;
|
|
37588
|
+
}
|
|
37589
|
+
}
|
|
35855
37590
|
try {
|
|
35856
37591
|
await updateItem.mutateAsync({
|
|
35857
37592
|
datasetId,
|
|
35858
37593
|
itemId: item.id,
|
|
35859
37594
|
input: parsedInput,
|
|
35860
|
-
groundTruth: parsedGroundTruth
|
|
37595
|
+
groundTruth: parsedGroundTruth,
|
|
37596
|
+
expectedTrajectory: parsedTrajectory
|
|
35861
37597
|
});
|
|
35862
37598
|
toast.success("Item updated");
|
|
35863
37599
|
setIsEditing(false);
|
|
35864
37600
|
} catch (error) {
|
|
35865
37601
|
toast.error(`Failed to update: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
35866
37602
|
}
|
|
35867
|
-
}, [inputValue, groundTruthValue, datasetId, item.id, updateItem]);
|
|
37603
|
+
}, [inputValue, groundTruthValue, trajectoryValue, datasetId, item.id, updateItem]);
|
|
35868
37604
|
if (isEditing) {
|
|
35869
37605
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 pb-3 pl-10 space-y-2", children: [
|
|
35870
37606
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
@@ -35892,6 +37628,19 @@ function ExpandedItemEditor({
|
|
|
35892
37628
|
}
|
|
35893
37629
|
)
|
|
35894
37630
|
] }),
|
|
37631
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
37632
|
+
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3 font-medium", children: "Expected Trajectory (JSON)" }),
|
|
37633
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37634
|
+
Textarea,
|
|
37635
|
+
{
|
|
37636
|
+
value: trajectoryValue,
|
|
37637
|
+
onChange: (e) => setTrajectoryValue(e.target.value),
|
|
37638
|
+
className: "mt-1 font-mono text-xs",
|
|
37639
|
+
rows: 3,
|
|
37640
|
+
placeholder: "Optional — JSON trajectory expectation"
|
|
37641
|
+
}
|
|
37642
|
+
)
|
|
37643
|
+
] }),
|
|
35895
37644
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-1", children: [
|
|
35896
37645
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "cta", size: "sm", onClick: handleSave, disabled: updateItem.isPending, children: [
|
|
35897
37646
|
updateItem.isPending ? /* @__PURE__ */ jsxRuntime.jsx(Spinner, { className: "h-3 w-3" }) : /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, {}) }),
|
|
@@ -35913,6 +37662,10 @@ function ExpandedItemEditor({
|
|
|
35913
37662
|
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3 font-medium", children: "Ground Truth" }),
|
|
35914
37663
|
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-neutral5 bg-surface1 rounded px-2 py-1.5 overflow-x-auto whitespace-pre-wrap wrap-break-word max-h-48 overflow-y-auto mt-1", children: formatValue$4(item.groundTruth) })
|
|
35915
37664
|
] }),
|
|
37665
|
+
item.expectedTrajectory != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
37666
|
+
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3 font-medium", children: "Expected Trajectory" }),
|
|
37667
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-xs text-neutral5 bg-surface1 rounded px-2 py-1.5 overflow-x-auto whitespace-pre-wrap break-words max-h-48 overflow-y-auto mt-1", children: formatValue$4(item.expectedTrajectory) })
|
|
37668
|
+
] }),
|
|
35916
37669
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 pt-1", children: [
|
|
35917
37670
|
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "ghost", size: "sm", onClick: startEditing, children: [
|
|
35918
37671
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: "sm", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, {}) }),
|
|
@@ -35973,12 +37726,14 @@ function ScorerDetailView({
|
|
|
35973
37726
|
const name = scorerData.scorer?.name || scorerId;
|
|
35974
37727
|
const description = scorerData.scorer?.description;
|
|
35975
37728
|
const isCode = scorerData.source === "code";
|
|
37729
|
+
const isTrajectory = scorerData.scorer?.config?.type === "trajectory";
|
|
35976
37730
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
35977
37731
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-border1 space-y-3", children: [
|
|
35978
37732
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
35979
37733
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
35980
37734
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
35981
37735
|
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-sm", className: "text-neutral5 font-medium truncate", children: name }),
|
|
37736
|
+
isTrajectory && /* @__PURE__ */ jsxRuntime.jsx(Chip, { size: "small", color: "purple", children: "trajectory" }),
|
|
35982
37737
|
isCode && /* @__PURE__ */ jsxRuntime.jsx("span", { title: "Defined in code — cannot be edited in the UI", children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", children: "Code" }) })
|
|
35983
37738
|
] }),
|
|
35984
37739
|
description && /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3 block mt-1", children: description })
|
|
@@ -36001,6 +37756,7 @@ function ScorerDetailView({
|
|
|
36001
37756
|
/* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-xs", className: "text-neutral3 font-medium uppercase tracking-wider block mb-2", children: "Details" }),
|
|
36002
37757
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
36003
37758
|
/* @__PURE__ */ jsxRuntime.jsx(DetailRow, { label: "ID", value: scorerId }),
|
|
37759
|
+
/* @__PURE__ */ jsxRuntime.jsx(DetailRow, { label: "Type", value: isTrajectory ? "Trajectory" : "Agent" }),
|
|
36004
37760
|
/* @__PURE__ */ jsxRuntime.jsx(DetailRow, { label: "Source", value: isCode ? "Code" : "Stored" }),
|
|
36005
37761
|
scorerData.agentIds && scorerData.agentIds.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
36006
37762
|
DetailRow,
|
|
@@ -39466,6 +41222,197 @@ function extractErrorText(error) {
|
|
|
39466
41222
|
return "Error";
|
|
39467
41223
|
}
|
|
39468
41224
|
|
|
41225
|
+
function BulkTraceReviewDialog({
|
|
41226
|
+
isOpen,
|
|
41227
|
+
onClose,
|
|
41228
|
+
datasetId,
|
|
41229
|
+
datasetName,
|
|
41230
|
+
initialItems
|
|
41231
|
+
}) {
|
|
41232
|
+
const [items, setItems] = React.useState(initialItems);
|
|
41233
|
+
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
41234
|
+
const { batchInsertItems } = useDatasetMutations();
|
|
41235
|
+
React.useEffect(() => {
|
|
41236
|
+
if (isOpen) {
|
|
41237
|
+
setItems(initialItems);
|
|
41238
|
+
setCurrentIndex(0);
|
|
41239
|
+
}
|
|
41240
|
+
}, [isOpen]);
|
|
41241
|
+
const currentItem = items[currentIndex];
|
|
41242
|
+
const total = items.length;
|
|
41243
|
+
const updateCurrentItem = React.useCallback(
|
|
41244
|
+
(field, value) => {
|
|
41245
|
+
setItems((prev) => prev.map((item, i) => i === currentIndex ? { ...item, [field]: value } : item));
|
|
41246
|
+
},
|
|
41247
|
+
[currentIndex]
|
|
41248
|
+
);
|
|
41249
|
+
const removeCurrentItem = React.useCallback(() => {
|
|
41250
|
+
setItems((prev) => {
|
|
41251
|
+
const next = prev.filter((_, i) => i !== currentIndex);
|
|
41252
|
+
if (next.length === 0) {
|
|
41253
|
+
onClose();
|
|
41254
|
+
return prev;
|
|
41255
|
+
}
|
|
41256
|
+
setCurrentIndex((idx) => Math.min(idx, next.length - 1));
|
|
41257
|
+
return next;
|
|
41258
|
+
});
|
|
41259
|
+
}, [currentIndex, onClose]);
|
|
41260
|
+
const handleSubmit = async () => {
|
|
41261
|
+
const parsed = [];
|
|
41262
|
+
for (let i = 0; i < items.length; i++) {
|
|
41263
|
+
const item = items[i];
|
|
41264
|
+
let parsedInput;
|
|
41265
|
+
try {
|
|
41266
|
+
parsedInput = JSON.parse(item.input);
|
|
41267
|
+
} catch {
|
|
41268
|
+
toast.error(`Item ${i + 1}: Input must be valid JSON`);
|
|
41269
|
+
setCurrentIndex(i);
|
|
41270
|
+
return;
|
|
41271
|
+
}
|
|
41272
|
+
let parsedGroundTruth;
|
|
41273
|
+
if (item.groundTruth.trim()) {
|
|
41274
|
+
try {
|
|
41275
|
+
parsedGroundTruth = JSON.parse(item.groundTruth);
|
|
41276
|
+
} catch {
|
|
41277
|
+
toast.error(`Item ${i + 1}: Ground Truth must be valid JSON`);
|
|
41278
|
+
setCurrentIndex(i);
|
|
41279
|
+
return;
|
|
41280
|
+
}
|
|
41281
|
+
}
|
|
41282
|
+
let parsedTrajectory;
|
|
41283
|
+
if (item.expectedTrajectory.trim()) {
|
|
41284
|
+
try {
|
|
41285
|
+
parsedTrajectory = JSON.parse(item.expectedTrajectory);
|
|
41286
|
+
} catch {
|
|
41287
|
+
toast.error(`Item ${i + 1}: Expected Trajectory must be valid JSON`);
|
|
41288
|
+
setCurrentIndex(i);
|
|
41289
|
+
return;
|
|
41290
|
+
}
|
|
41291
|
+
}
|
|
41292
|
+
parsed.push({
|
|
41293
|
+
input: parsedInput,
|
|
41294
|
+
groundTruth: parsedGroundTruth,
|
|
41295
|
+
expectedTrajectory: parsedTrajectory,
|
|
41296
|
+
...item.source ? { source: item.source } : {}
|
|
41297
|
+
});
|
|
41298
|
+
}
|
|
41299
|
+
try {
|
|
41300
|
+
await batchInsertItems.mutateAsync({ datasetId, items: parsed });
|
|
41301
|
+
toast.success(`Added ${parsed.length} item${parsed.length !== 1 ? "s" : ""} to "${datasetName}"`);
|
|
41302
|
+
onClose();
|
|
41303
|
+
} catch {
|
|
41304
|
+
toast.error("Failed to add items to dataset");
|
|
41305
|
+
}
|
|
41306
|
+
};
|
|
41307
|
+
if (!currentItem) return null;
|
|
41308
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
41309
|
+
SideDialog,
|
|
41310
|
+
{
|
|
41311
|
+
dialogTitle: "Review items before adding to dataset",
|
|
41312
|
+
dialogDescription: `Reviewing ${total} item${total !== 1 ? "s" : ""} for dataset "${datasetName}"`,
|
|
41313
|
+
isOpen,
|
|
41314
|
+
onClose,
|
|
41315
|
+
level: 1,
|
|
41316
|
+
children: [
|
|
41317
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SideDialog.Top, { children: [
|
|
41318
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DatabaseIcon, { className: "size-4" }),
|
|
41319
|
+
" Review ",
|
|
41320
|
+
total,
|
|
41321
|
+
" item",
|
|
41322
|
+
total !== 1 ? "s" : "",
|
|
41323
|
+
" → ",
|
|
41324
|
+
datasetName
|
|
41325
|
+
] }),
|
|
41326
|
+
/* @__PURE__ */ jsxRuntime.jsxs(SideDialog.Content, { children: [
|
|
41327
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
41328
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
41329
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41330
|
+
IconButton,
|
|
41331
|
+
{
|
|
41332
|
+
tooltip: "Previous item",
|
|
41333
|
+
variant: "outline",
|
|
41334
|
+
size: "sm",
|
|
41335
|
+
disabled: currentIndex === 0,
|
|
41336
|
+
onClick: () => setCurrentIndex((prev) => prev - 1),
|
|
41337
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeftIcon, {})
|
|
41338
|
+
}
|
|
41339
|
+
),
|
|
41340
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Txt, { variant: "ui-sm", className: "text-icon3 tabular-nums", children: [
|
|
41341
|
+
currentIndex + 1,
|
|
41342
|
+
" / ",
|
|
41343
|
+
total
|
|
41344
|
+
] }),
|
|
41345
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41346
|
+
IconButton,
|
|
41347
|
+
{
|
|
41348
|
+
tooltip: "Next item",
|
|
41349
|
+
variant: "outline",
|
|
41350
|
+
size: "sm",
|
|
41351
|
+
disabled: currentIndex === total - 1,
|
|
41352
|
+
onClick: () => setCurrentIndex((prev) => prev + 1),
|
|
41353
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, {})
|
|
41354
|
+
}
|
|
41355
|
+
)
|
|
41356
|
+
] }),
|
|
41357
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton, { tooltip: "Remove this item", variant: "ghost", size: "sm", onClick: removeCurrentItem, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TrashIcon, {}) })
|
|
41358
|
+
] }),
|
|
41359
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4", children: [
|
|
41360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
41361
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Input (JSON) *" }),
|
|
41362
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41363
|
+
CodeEditor,
|
|
41364
|
+
{
|
|
41365
|
+
value: currentItem.input,
|
|
41366
|
+
onChange: (v) => updateCurrentItem("input", v),
|
|
41367
|
+
showCopyButton: false,
|
|
41368
|
+
className: "min-h-[120px]"
|
|
41369
|
+
}
|
|
41370
|
+
)
|
|
41371
|
+
] }),
|
|
41372
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
41373
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Ground Truth (JSON, optional)" }),
|
|
41374
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41375
|
+
CodeEditor,
|
|
41376
|
+
{
|
|
41377
|
+
value: currentItem.groundTruth,
|
|
41378
|
+
onChange: (v) => updateCurrentItem("groundTruth", v),
|
|
41379
|
+
showCopyButton: false,
|
|
41380
|
+
className: "min-h-[80px]"
|
|
41381
|
+
}
|
|
41382
|
+
)
|
|
41383
|
+
] }),
|
|
41384
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2", children: [
|
|
41385
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Expected Trajectory (JSON, optional)" }),
|
|
41386
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
41387
|
+
CodeEditor,
|
|
41388
|
+
{
|
|
41389
|
+
value: currentItem.expectedTrajectory,
|
|
41390
|
+
onChange: (v) => updateCurrentItem("expectedTrajectory", v),
|
|
41391
|
+
showCopyButton: false,
|
|
41392
|
+
className: "min-h-[80px]"
|
|
41393
|
+
}
|
|
41394
|
+
)
|
|
41395
|
+
] }),
|
|
41396
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 pt-4", children: [
|
|
41397
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", variant: "outline", onClick: onClose, children: "Cancel" }),
|
|
41398
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "light", disabled: batchInsertItems.isPending, onClick: handleSubmit, children: batchInsertItems.isPending ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
41399
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2Icon, { className: "size-4 animate-spin" }),
|
|
41400
|
+
"Adding..."
|
|
41401
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
41402
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.DatabaseIcon, { className: "size-4" }),
|
|
41403
|
+
"Add all ",
|
|
41404
|
+
total,
|
|
41405
|
+
" item",
|
|
41406
|
+
total !== 1 ? "s" : ""
|
|
41407
|
+
] }) })
|
|
41408
|
+
] })
|
|
41409
|
+
] })
|
|
41410
|
+
] })
|
|
41411
|
+
]
|
|
41412
|
+
}
|
|
41413
|
+
);
|
|
41414
|
+
}
|
|
41415
|
+
|
|
39469
41416
|
function EntityListPageLayoutRoot({ children, className }) {
|
|
39470
41417
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39471
41418
|
"div",
|
|
@@ -39559,16 +41506,6 @@ function extractInputPreview(input) {
|
|
|
39559
41506
|
if (typeof obj.input === "string") return obj.input;
|
|
39560
41507
|
return JSON.stringify(input).slice(0, 200);
|
|
39561
41508
|
}
|
|
39562
|
-
function extractRawInput(input) {
|
|
39563
|
-
if (!input || typeof input !== "object") return input;
|
|
39564
|
-
const obj = input;
|
|
39565
|
-
if (obj.messages && Array.isArray(obj.messages)) {
|
|
39566
|
-
const userMsgs = obj.messages.filter((m) => m.role === "user");
|
|
39567
|
-
const last = userMsgs[userMsgs.length - 1];
|
|
39568
|
-
if (last?.content) return last.content;
|
|
39569
|
-
}
|
|
39570
|
-
return input;
|
|
39571
|
-
}
|
|
39572
41509
|
function extractOutputPreview(output) {
|
|
39573
41510
|
if (!output) return "";
|
|
39574
41511
|
if (typeof output === "string") return output;
|
|
@@ -39754,11 +41691,31 @@ function BulkAddToDatasetBar({
|
|
|
39754
41691
|
] })
|
|
39755
41692
|
] });
|
|
39756
41693
|
}
|
|
39757
|
-
function AgentTracesPanel({
|
|
41694
|
+
function AgentTracesPanel({
|
|
41695
|
+
agentId,
|
|
41696
|
+
basePath,
|
|
41697
|
+
initialTraceId,
|
|
41698
|
+
initialSpanId,
|
|
41699
|
+
initialSpanTab,
|
|
41700
|
+
initialScoreId
|
|
41701
|
+
}) {
|
|
39758
41702
|
const client = react.useMastraClient();
|
|
39759
41703
|
const filters = useAgentTracesFilters(agentId);
|
|
39760
|
-
const
|
|
39761
|
-
const
|
|
41704
|
+
const { navigate } = useLinkComponent();
|
|
41705
|
+
const buildTraceUrl = React.useCallback(
|
|
41706
|
+
(traceId, spanId, scoreId, tab) => {
|
|
41707
|
+
const params = new URLSearchParams();
|
|
41708
|
+
if (traceId) params.set("traceId", traceId);
|
|
41709
|
+
if (spanId) params.set("spanId", spanId);
|
|
41710
|
+
if (tab) params.set("tab", tab);
|
|
41711
|
+
if (scoreId) params.set("scoreId", scoreId);
|
|
41712
|
+
const query = params.toString();
|
|
41713
|
+
return query ? `${basePath ?? `/agents/${agentId}/traces`}?${query}` : basePath ?? `/agents/${agentId}/traces`;
|
|
41714
|
+
},
|
|
41715
|
+
[agentId, basePath]
|
|
41716
|
+
);
|
|
41717
|
+
const [selectedTraceId, setSelectedTraceId] = React.useState(initialTraceId);
|
|
41718
|
+
const [dialogIsOpen, setDialogIsOpen] = React.useState(Boolean(initialTraceId));
|
|
39762
41719
|
const [checkedTraceIds, setCheckedTraceIds] = React.useState(/* @__PURE__ */ new Set());
|
|
39763
41720
|
const [sort, setSort] = React.useState(null);
|
|
39764
41721
|
const {
|
|
@@ -39871,20 +41828,32 @@ function AgentTracesPanel({ agentId }) {
|
|
|
39871
41828
|
return next.size === prev.size ? prev : next;
|
|
39872
41829
|
});
|
|
39873
41830
|
}, [displayTraces, checkedTraceIds.size]);
|
|
39874
|
-
const {
|
|
41831
|
+
const [bulkReview, setBulkReview] = React.useState({ isOpen: false, datasetId: "", datasetName: "", items: [] });
|
|
41832
|
+
const [isPreparing, setIsPreparing] = React.useState(false);
|
|
41833
|
+
React.useEffect(() => {
|
|
41834
|
+
if (initialTraceId) {
|
|
41835
|
+
setSelectedTraceId(initialTraceId);
|
|
41836
|
+
setDialogIsOpen(true);
|
|
41837
|
+
return;
|
|
41838
|
+
}
|
|
41839
|
+
setSelectedTraceId(void 0);
|
|
41840
|
+
setDialogIsOpen(false);
|
|
41841
|
+
}, [initialTraceId]);
|
|
39875
41842
|
const allSelected = displayTraces.length > 0 && displayTraces.every((t) => checkedTraceIds.has(t.traceId));
|
|
39876
41843
|
const someSelected = checkedTraceIds.size > 0;
|
|
39877
41844
|
const handleTraceClick = React.useCallback(
|
|
39878
41845
|
(traceId) => {
|
|
39879
41846
|
if (selectedTraceId === traceId) {
|
|
41847
|
+
navigate(buildTraceUrl());
|
|
39880
41848
|
setSelectedTraceId(void 0);
|
|
39881
41849
|
setDialogIsOpen(false);
|
|
39882
41850
|
} else {
|
|
41851
|
+
navigate(buildTraceUrl(traceId));
|
|
39883
41852
|
setSelectedTraceId(traceId);
|
|
39884
41853
|
setDialogIsOpen(true);
|
|
39885
41854
|
}
|
|
39886
41855
|
},
|
|
39887
|
-
[selectedTraceId]
|
|
41856
|
+
[buildTraceUrl, navigate, selectedTraceId]
|
|
39888
41857
|
);
|
|
39889
41858
|
const handleCheckToggle = React.useCallback((traceId, checked) => {
|
|
39890
41859
|
setCheckedTraceIds((prev) => {
|
|
@@ -39904,33 +41873,67 @@ function AgentTracesPanel({ agentId }) {
|
|
|
39904
41873
|
setCheckedTraceIds(new Set(displayTraces.map((t) => t.traceId)));
|
|
39905
41874
|
}
|
|
39906
41875
|
}, [allSelected, displayTraces]);
|
|
41876
|
+
const { data: allDatasets } = useDatasets();
|
|
39907
41877
|
const handleBulkAdd = React.useCallback(
|
|
39908
41878
|
async (datasetId) => {
|
|
39909
41879
|
const selected = displayTraces.filter((t) => checkedTraceIds.has(t.traceId));
|
|
39910
41880
|
if (!selected.length) return;
|
|
39911
|
-
|
|
39912
|
-
input: extractRawInput(t.input),
|
|
39913
|
-
groundTruth: t.output ?? void 0,
|
|
39914
|
-
source: { type: "trace", referenceId: t.traceId }
|
|
39915
|
-
}));
|
|
41881
|
+
setIsPreparing(true);
|
|
39916
41882
|
try {
|
|
39917
|
-
|
|
39918
|
-
|
|
39919
|
-
|
|
39920
|
-
|
|
39921
|
-
|
|
41883
|
+
const BATCH_SIZE = 5;
|
|
41884
|
+
const trajectories = [];
|
|
41885
|
+
for (let i = 0; i < selected.length; i += BATCH_SIZE) {
|
|
41886
|
+
const batch = selected.slice(i, i + BATCH_SIZE);
|
|
41887
|
+
const results = await Promise.all(
|
|
41888
|
+
batch.map((t) => client.getTraceTrajectory(t.traceId).catch(() => void 0))
|
|
41889
|
+
);
|
|
41890
|
+
trajectories.push(...results);
|
|
41891
|
+
}
|
|
41892
|
+
const items = selected.map((t, i) => {
|
|
41893
|
+
const trajectory = trajectories[i];
|
|
41894
|
+
let trajectoryExpectation;
|
|
41895
|
+
if (trajectory?.steps && trajectory.steps.length > 0) {
|
|
41896
|
+
trajectoryExpectation = {
|
|
41897
|
+
steps: trajectory.steps.map((step) => {
|
|
41898
|
+
const { name, stepType, ...rest } = step;
|
|
41899
|
+
const expected = { name, stepType };
|
|
41900
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
41901
|
+
if (v != null && k !== "durationMs" && k !== "metadata" && k !== "children") {
|
|
41902
|
+
expected[k] = v;
|
|
41903
|
+
}
|
|
41904
|
+
}
|
|
41905
|
+
return expected;
|
|
41906
|
+
}),
|
|
41907
|
+
ordering: "relaxed"
|
|
41908
|
+
};
|
|
41909
|
+
}
|
|
41910
|
+
const formatJson = (val) => val != null ? JSON.stringify(val, null, 2) : "";
|
|
41911
|
+
const rawInput = t.spanType === "agent_run" && t.input && typeof t.input === "object" && !Array.isArray(t.input) && Array.isArray(t.input.messages) ? t.input.messages : t.input;
|
|
41912
|
+
return {
|
|
41913
|
+
input: formatJson(rawInput),
|
|
41914
|
+
groundTruth: formatJson(t.output),
|
|
41915
|
+
expectedTrajectory: formatJson(trajectoryExpectation),
|
|
41916
|
+
source: { type: "trace", referenceId: t.traceId }
|
|
41917
|
+
};
|
|
41918
|
+
});
|
|
41919
|
+
const datasetName = allDatasets?.datasets?.find((d) => d.id === datasetId)?.name ?? "dataset";
|
|
41920
|
+
setBulkReview({ isOpen: true, datasetId, datasetName, items });
|
|
41921
|
+
} finally {
|
|
41922
|
+
setIsPreparing(false);
|
|
39922
41923
|
}
|
|
39923
41924
|
},
|
|
39924
|
-
[displayTraces, checkedTraceIds,
|
|
41925
|
+
[displayTraces, checkedTraceIds, client, allDatasets]
|
|
41926
|
+
);
|
|
41927
|
+
const computeTraceLink = React.useCallback(
|
|
41928
|
+
(traceId, spanId, tab) => buildTraceUrl(traceId, spanId, void 0, tab),
|
|
41929
|
+
[buildTraceUrl]
|
|
39925
41930
|
);
|
|
39926
|
-
const computeTraceLink = React.useCallback((traceId, spanId) => {
|
|
39927
|
-
return `/observability?traceId=${traceId}${spanId ? `&spanId=${spanId}` : ""}`;
|
|
39928
|
-
}, []);
|
|
39929
41931
|
const toNextTrace = React.useMemo(
|
|
39930
41932
|
() => getToNextEntryFn({
|
|
39931
41933
|
entries: displayTraces.map((t) => ({ id: t.traceId })),
|
|
39932
41934
|
id: selectedTraceId,
|
|
39933
41935
|
update: (id) => {
|
|
41936
|
+
navigate(buildTraceUrl(id));
|
|
39934
41937
|
setSelectedTraceId(id);
|
|
39935
41938
|
setDialogIsOpen(true);
|
|
39936
41939
|
}
|
|
@@ -39942,6 +41945,7 @@ function AgentTracesPanel({ agentId }) {
|
|
|
39942
41945
|
entries: displayTraces.map((t) => ({ id: t.traceId })),
|
|
39943
41946
|
id: selectedTraceId,
|
|
39944
41947
|
update: (id) => {
|
|
41948
|
+
navigate(buildTraceUrl(id));
|
|
39945
41949
|
setSelectedTraceId(id);
|
|
39946
41950
|
setDialogIsOpen(true);
|
|
39947
41951
|
}
|
|
@@ -39958,14 +41962,7 @@ function AgentTracesPanel({ agentId }) {
|
|
|
39958
41962
|
}
|
|
39959
41963
|
return /* @__PURE__ */ jsxRuntime.jsxs(EntityListPageLayout, { children: [
|
|
39960
41964
|
/* @__PURE__ */ jsxRuntime.jsx(EntityListPageLayout.Top, { children: /* @__PURE__ */ jsxRuntime.jsx(AgentTracesToolbar, { filters, scorerOptions }) }),
|
|
39961
|
-
someSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
39962
|
-
BulkAddToDatasetBar,
|
|
39963
|
-
{
|
|
39964
|
-
selectedCount: checkedTraceIds.size,
|
|
39965
|
-
onAdd: handleBulkAdd,
|
|
39966
|
-
isPending: batchInsertItems.isPending
|
|
39967
|
-
}
|
|
39968
|
-
),
|
|
41965
|
+
someSelected && /* @__PURE__ */ jsxRuntime.jsx(BulkAddToDatasetBar, { selectedCount: checkedTraceIds.size, onAdd: handleBulkAdd, isPending: isPreparing }),
|
|
39969
41966
|
isTracesLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) : displayTraces.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
39970
41967
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsxRuntime.jsx(Txt, { variant: "ui-md", className: "text-icon3", children: filters.filtersApplied ? "No traces match the current filters." : "No traces yet." }) }),
|
|
39971
41968
|
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: setEndOfListElement, className: "h-1", children: isFetchingNextPage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center py-4", children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}) }) })
|
|
@@ -40043,6 +42040,7 @@ function AgentTracesPanel({ agentId }) {
|
|
|
40043
42040
|
traceDetails: selectedTrace?.spans?.find((s) => s.traceId === selectedTraceId && !s.parentSpanId),
|
|
40044
42041
|
isOpen: dialogIsOpen,
|
|
40045
42042
|
onClose: () => {
|
|
42043
|
+
navigate(buildTraceUrl());
|
|
40046
42044
|
setDialogIsOpen(false);
|
|
40047
42045
|
setSelectedTraceId(void 0);
|
|
40048
42046
|
},
|
|
@@ -40050,9 +42048,25 @@ function AgentTracesPanel({ agentId }) {
|
|
|
40050
42048
|
onPrevious: toPreviousTrace,
|
|
40051
42049
|
isLoadingSpans: isSelectedTraceLoading,
|
|
40052
42050
|
computeTraceLink,
|
|
42051
|
+
initialSpanId,
|
|
42052
|
+
initialSpanTab,
|
|
42053
|
+
initialScoreId,
|
|
40053
42054
|
scorers: scorersMap,
|
|
40054
42055
|
isLoadingScorers
|
|
40055
42056
|
}
|
|
42057
|
+
),
|
|
42058
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42059
|
+
BulkTraceReviewDialog,
|
|
42060
|
+
{
|
|
42061
|
+
isOpen: bulkReview.isOpen,
|
|
42062
|
+
onClose: () => {
|
|
42063
|
+
setBulkReview((prev) => ({ ...prev, isOpen: false }));
|
|
42064
|
+
setCheckedTraceIds(/* @__PURE__ */ new Set());
|
|
42065
|
+
},
|
|
42066
|
+
datasetId: bulkReview.datasetId,
|
|
42067
|
+
datasetName: bulkReview.datasetName,
|
|
42068
|
+
initialItems: bulkReview.items
|
|
42069
|
+
}
|
|
40056
42070
|
)
|
|
40057
42071
|
] });
|
|
40058
42072
|
}
|
|
@@ -41906,7 +43920,7 @@ function MetricsCardRoot({ children, className }) {
|
|
|
41906
43920
|
DashboardCard,
|
|
41907
43921
|
{
|
|
41908
43922
|
className: cn(
|
|
41909
|
-
"flex-1 grid grid-rows-[
|
|
43923
|
+
"flex-1 grid grid-rows-[4rem_1fr] min-h-72 gap-2 min-w-80 md:min-w-[22rem] lg:min-w-[24rem] xl:min-w-[26rem] 2xl:min-w-[30rem]",
|
|
41910
43924
|
className
|
|
41911
43925
|
),
|
|
41912
43926
|
children
|
|
@@ -42057,12 +44071,12 @@ function MetricsLineChart({
|
|
|
42057
44071
|
yDomain
|
|
42058
44072
|
}) {
|
|
42059
44073
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
42060
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap w-full items-end gap-4 gap-y-1 mb-4", children: series.map((s) => {
|
|
44074
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap w-full items-end gap-4 gap-y-1 mb-4 ", children: series.map((s) => {
|
|
42061
44075
|
const aggregated = s.aggregate?.(data);
|
|
42062
44076
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-baseline gap-2", children: [
|
|
42063
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-2 shrink-0 rounded-full translate-y-
|
|
44077
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-2 shrink-0 rounded-full -translate-y-px", style: { backgroundColor: s.color } }),
|
|
42064
44078
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-sm text-neutral3 truncate max-w-24", children: s.label }),
|
|
42065
|
-
aggregated && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-
|
|
44079
|
+
aggregated && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-sm text-neutral4", children: [
|
|
42066
44080
|
aggregated.value,
|
|
42067
44081
|
aggregated.suffix && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-sm text-neutral2", children: [
|
|
42068
44082
|
" ",
|
|
@@ -42072,7 +44086,15 @@ function MetricsLineChart({
|
|
|
42072
44086
|
] }, s.dataKey);
|
|
42073
44087
|
}) }),
|
|
42074
44088
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { height }, children: /* @__PURE__ */ jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxRuntime.jsxs(recharts.LineChart, { data, children: [
|
|
42075
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44089
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44090
|
+
recharts.CartesianGrid,
|
|
44091
|
+
{
|
|
44092
|
+
stroke: "currentColor",
|
|
44093
|
+
strokeOpacity: 0.08,
|
|
44094
|
+
vertical: false,
|
|
44095
|
+
className: "text-black dark:text-white"
|
|
44096
|
+
}
|
|
44097
|
+
),
|
|
42076
44098
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
42077
44099
|
recharts.XAxis,
|
|
42078
44100
|
{
|
|
@@ -42183,24 +44205,25 @@ function useAvgScoreKpiMetrics() {
|
|
|
42183
44205
|
if (scorerIds.length === 0) {
|
|
42184
44206
|
return { value: null, previousValue: null, changePercent: null };
|
|
42185
44207
|
}
|
|
42186
|
-
const
|
|
42187
|
-
|
|
44208
|
+
const filters = {
|
|
44209
|
+
timestamp: { start: timestamp.start, end: timestamp.end }
|
|
44210
|
+
};
|
|
44211
|
+
const results = await Promise.all(
|
|
44212
|
+
scorerIds.map(async (scorerId) => {
|
|
44213
|
+
const [avg2, count] = await Promise.all([
|
|
44214
|
+
client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
|
|
44215
|
+
client.getScoreAggregate({ scorerId, aggregation: "count", filters })
|
|
44216
|
+
]);
|
|
44217
|
+
return { avg: avg2.value ?? 0, count: count.value ?? 0 };
|
|
44218
|
+
})
|
|
42188
44219
|
);
|
|
42189
|
-
const
|
|
42190
|
-
|
|
42191
|
-
const allScoreValues = [];
|
|
42192
|
-
for (const result of allResults) {
|
|
42193
|
-
for (const s of result?.scores ?? []) {
|
|
42194
|
-
const ts = new Date(s.createdAt).getTime();
|
|
42195
|
-
if (ts >= startMs && ts <= endMs) {
|
|
42196
|
-
allScoreValues.push(s.score);
|
|
42197
|
-
}
|
|
42198
|
-
}
|
|
42199
|
-
}
|
|
42200
|
-
if (allScoreValues.length === 0) {
|
|
44220
|
+
const withData = results.filter((r) => r.count > 0);
|
|
44221
|
+
if (withData.length === 0) {
|
|
42201
44222
|
return { value: null, previousValue: null, changePercent: null };
|
|
42202
44223
|
}
|
|
42203
|
-
const
|
|
44224
|
+
const totalCount = withData.reduce((sum, r) => sum + r.count, 0);
|
|
44225
|
+
const weightedSum = withData.reduce((sum, r) => sum + r.avg * r.count, 0);
|
|
44226
|
+
const avg = weightedSum / totalCount;
|
|
42204
44227
|
return { value: Math.round(avg * 100) / 100, previousValue: null, changePercent: null };
|
|
42205
44228
|
}
|
|
42206
44229
|
});
|
|
@@ -42479,78 +44502,84 @@ function useScoresMetrics() {
|
|
|
42479
44502
|
return reactQuery.useQuery({
|
|
42480
44503
|
queryKey: ["metrics", "scores-card", datePreset, customRange],
|
|
42481
44504
|
queryFn: async () => {
|
|
44505
|
+
const filters = {
|
|
44506
|
+
timestamp: { start: timestamp.start, end: timestamp.end }
|
|
44507
|
+
};
|
|
42482
44508
|
const scorersMap = await client.listScorers();
|
|
42483
44509
|
const scorerIds = Object.keys(scorersMap ?? {});
|
|
42484
44510
|
if (scorerIds.length === 0) {
|
|
42485
44511
|
return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
|
|
42486
44512
|
}
|
|
42487
|
-
const
|
|
42488
|
-
|
|
42489
|
-
|
|
44513
|
+
const summaryResults = await Promise.all(
|
|
44514
|
+
scorerIds.map(async (scorerId) => {
|
|
44515
|
+
const [avg, min, max, count] = await Promise.all([
|
|
44516
|
+
client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
|
|
44517
|
+
client.getScoreAggregate({ scorerId, aggregation: "min", filters }),
|
|
44518
|
+
client.getScoreAggregate({ scorerId, aggregation: "max", filters }),
|
|
44519
|
+
client.getScoreAggregate({ scorerId, aggregation: "count", filters })
|
|
44520
|
+
]);
|
|
44521
|
+
return {
|
|
44522
|
+
scorer: scorerId,
|
|
44523
|
+
avg: avg.value ?? 0,
|
|
44524
|
+
min: min.value ?? 0,
|
|
44525
|
+
max: max.value ?? 0,
|
|
44526
|
+
count: count.value ?? 0
|
|
44527
|
+
};
|
|
44528
|
+
})
|
|
42490
44529
|
);
|
|
42491
|
-
const
|
|
42492
|
-
const endMs = timestamp.end.getTime();
|
|
42493
|
-
const allScores = [];
|
|
42494
|
-
for (let i = 0; i < scorerIds.length; i++) {
|
|
42495
|
-
const scores = allResults[i]?.scores ?? [];
|
|
42496
|
-
for (const s of scores) {
|
|
42497
|
-
const ts = new Date(s.createdAt).getTime();
|
|
42498
|
-
if (ts >= startMs && ts <= endMs) {
|
|
42499
|
-
allScores.push({
|
|
42500
|
-
scorerId: scorerIds[i],
|
|
42501
|
-
score: s.score,
|
|
42502
|
-
createdAt: s.createdAt
|
|
42503
|
-
});
|
|
42504
|
-
}
|
|
42505
|
-
}
|
|
42506
|
-
}
|
|
42507
|
-
if (allScores.length === 0) {
|
|
42508
|
-
return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
|
|
42509
|
-
}
|
|
42510
|
-
const byScorer = /* @__PURE__ */ new Map();
|
|
42511
|
-
for (const s of allScores) {
|
|
42512
|
-
if (!byScorer.has(s.scorerId)) byScorer.set(s.scorerId, []);
|
|
42513
|
-
byScorer.get(s.scorerId).push(s.score);
|
|
42514
|
-
}
|
|
42515
|
-
const summaryData = Array.from(byScorer.entries()).map(([scorer, vals]) => ({
|
|
42516
|
-
scorer,
|
|
42517
|
-
avg: vals.reduce((a, b) => a + b, 0) / vals.length,
|
|
42518
|
-
min: Math.min(...vals),
|
|
42519
|
-
max: Math.max(...vals),
|
|
42520
|
-
count: vals.length
|
|
42521
|
-
}));
|
|
44530
|
+
const summaryData = summaryResults.filter((s) => s.count > 0);
|
|
42522
44531
|
const scorerNames = summaryData.map((s) => s.scorer);
|
|
42523
|
-
|
|
42524
|
-
|
|
42525
|
-
for (const s of allScores) {
|
|
42526
|
-
const ts = new Date(s.createdAt);
|
|
42527
|
-
const bucket = Math.floor(ts.getTime() / 36e5) * 36e5;
|
|
42528
|
-
if (!bucketMap.has(bucket)) bucketMap.set(bucket, /* @__PURE__ */ new Map());
|
|
42529
|
-
const scorerMap = bucketMap.get(bucket);
|
|
42530
|
-
if (!scorerMap.has(s.scorerId)) scorerMap.set(s.scorerId, []);
|
|
42531
|
-
scorerMap.get(s.scorerId).push(s.score);
|
|
44532
|
+
if (summaryData.length === 0) {
|
|
44533
|
+
return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
|
|
42532
44534
|
}
|
|
42533
|
-
const
|
|
42534
|
-
|
|
42535
|
-
|
|
42536
|
-
|
|
42537
|
-
|
|
42538
|
-
|
|
44535
|
+
const totalWeighted = summaryData.reduce((s, d) => s + d.avg * d.count, 0);
|
|
44536
|
+
const totalCount = summaryData.reduce((s, d) => s + d.count, 0);
|
|
44537
|
+
const avgScore = totalCount ? Math.round(totalWeighted / totalCount * 100) / 100 : 0;
|
|
44538
|
+
const interval = "1h";
|
|
44539
|
+
const timeSeriesResults = await Promise.all(
|
|
44540
|
+
scorerNames.map(
|
|
44541
|
+
(scorerId) => client.getScoreTimeSeries({
|
|
44542
|
+
scorerId,
|
|
44543
|
+
interval,
|
|
44544
|
+
aggregation: "avg",
|
|
44545
|
+
filters
|
|
42539
44546
|
})
|
|
42540
|
-
|
|
42541
|
-
|
|
42542
|
-
|
|
42543
|
-
|
|
42544
|
-
|
|
44547
|
+
)
|
|
44548
|
+
);
|
|
44549
|
+
const bucketMap = /* @__PURE__ */ new Map();
|
|
44550
|
+
const rangeSpansDays = timestamp.end.toDateString() !== timestamp.start.toDateString();
|
|
44551
|
+
for (let i = 0; i < scorerNames.length; i++) {
|
|
44552
|
+
const scorerId = scorerNames[i];
|
|
44553
|
+
const series = timeSeriesResults[i]?.series ?? [];
|
|
44554
|
+
for (const s of series) {
|
|
44555
|
+
for (const point of s.points) {
|
|
44556
|
+
const ts = new Date(point.timestamp);
|
|
44557
|
+
const key = ts.toISOString();
|
|
44558
|
+
if (!bucketMap.has(key)) {
|
|
44559
|
+
bucketMap.set(key, {
|
|
44560
|
+
time: rangeSpansDays ? ts.toLocaleString("en-US", {
|
|
44561
|
+
month: "short",
|
|
44562
|
+
day: "numeric",
|
|
44563
|
+
hour: "2-digit",
|
|
44564
|
+
minute: "2-digit",
|
|
44565
|
+
hour12: false
|
|
44566
|
+
}) : ts.toLocaleTimeString("en-US", {
|
|
44567
|
+
hour: "2-digit",
|
|
44568
|
+
minute: "2-digit",
|
|
44569
|
+
hour12: false
|
|
44570
|
+
})
|
|
44571
|
+
});
|
|
44572
|
+
}
|
|
44573
|
+
bucketMap.get(key)[scorerId] = +point.value.toFixed(2);
|
|
42545
44574
|
}
|
|
42546
44575
|
}
|
|
42547
|
-
|
|
42548
|
-
|
|
44576
|
+
}
|
|
44577
|
+
const overTimeData = Array.from(bucketMap.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, point]) => point);
|
|
42549
44578
|
return {
|
|
42550
44579
|
summaryData,
|
|
42551
44580
|
overTimeData,
|
|
42552
44581
|
scorerNames,
|
|
42553
|
-
avgScore
|
|
44582
|
+
avgScore
|
|
42554
44583
|
};
|
|
42555
44584
|
}
|
|
42556
44585
|
});
|
|
@@ -42595,7 +44624,7 @@ function ScoresCard() {
|
|
|
42595
44624
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "over-time", children: "Over Time" }),
|
|
42596
44625
|
/* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "summary", children: "Summary" })
|
|
42597
44626
|
] }),
|
|
42598
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "over-time", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
|
|
44627
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "over-time", className: "pb-0", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
|
|
42599
44628
|
/* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "summary", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42600
44629
|
MetricsDataTable,
|
|
42601
44630
|
{
|
|
@@ -42733,7 +44762,7 @@ function HorizontalBars({
|
|
|
42733
44762
|
"div",
|
|
42734
44763
|
{
|
|
42735
44764
|
className: cn(
|
|
42736
|
-
"absolute inset-y-0",
|
|
44765
|
+
"absolute inset-y-0 opacity-40 dark:opacity-100",
|
|
42737
44766
|
si === 0 && "rounded-l",
|
|
42738
44767
|
isLastWithValue && "rounded-r"
|
|
42739
44768
|
),
|
|
@@ -42749,7 +44778,7 @@ function HorizontalBars({
|
|
|
42749
44778
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42750
44779
|
"div",
|
|
42751
44780
|
{
|
|
42752
|
-
className: "absolute inset-y-0 left-0 rounded",
|
|
44781
|
+
className: "absolute inset-y-0 left-0 rounded opacity-40 dark:opacity-100",
|
|
42753
44782
|
style: { width: `${pct}%`, backgroundColor: seg.color }
|
|
42754
44783
|
},
|
|
42755
44784
|
seg.label
|
|
@@ -43845,6 +45874,9 @@ function SpanScoreList({
|
|
|
43845
45874
|
const score = scoresData?.scores?.find((s) => s?.id === scoreId);
|
|
43846
45875
|
setSelectedScore(score);
|
|
43847
45876
|
setDialogIsOpen(true);
|
|
45877
|
+
if (traceId) {
|
|
45878
|
+
navigate(`${computeTraceLink(traceId, spanId)}&tab=scores&scoreId=${encodeURIComponent(scoreId)}`);
|
|
45879
|
+
}
|
|
43848
45880
|
};
|
|
43849
45881
|
if (isLoadingScoresData) {
|
|
43850
45882
|
return /* @__PURE__ */ jsxRuntime.jsx(EntryListSkeleton, { columns: traceScoresListColumns });
|
|
@@ -46697,9 +48729,11 @@ function DatasetItemContent({ item }) {
|
|
|
46697
48729
|
const inputDisplay = item?.input ? JSON.stringify(item.input, null, 2) : "null";
|
|
46698
48730
|
const groundTruthDisplay = item?.groundTruth ? JSON.stringify(item.groundTruth, null, 2) : "null";
|
|
46699
48731
|
const metadataDisplay = item?.metadata ? JSON.stringify(item.metadata, null, 2) : "null";
|
|
48732
|
+
const trajectoryDisplay = item?.expectedTrajectory ? JSON.stringify(item.expectedTrajectory, null, 2) : null;
|
|
46700
48733
|
return /* @__PURE__ */ jsxRuntime.jsxs(Sections, { children: [
|
|
46701
48734
|
/* @__PURE__ */ jsxRuntime.jsx(SideDialog.CodeSection, { title: "Input", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileInputIcon, {}), codeStr: inputDisplay }),
|
|
46702
48735
|
/* @__PURE__ */ jsxRuntime.jsx(SideDialog.CodeSection, { title: "Ground Truth", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileOutputIcon, {}), codeStr: groundTruthDisplay }),
|
|
48736
|
+
trajectoryDisplay && /* @__PURE__ */ jsxRuntime.jsx(SideDialog.CodeSection, { title: "Expected Trajectory", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RouteIcon, {}), codeStr: trajectoryDisplay }),
|
|
46703
48737
|
/* @__PURE__ */ jsxRuntime.jsx(SideDialog.CodeSection, { title: "Metadata", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TagIcon, {}), codeStr: metadataDisplay })
|
|
46704
48738
|
] });
|
|
46705
48739
|
}
|
|
@@ -46722,6 +48756,8 @@ function EditModeContent({
|
|
|
46722
48756
|
setGroundTruthValue,
|
|
46723
48757
|
metadataValue,
|
|
46724
48758
|
setMetadataValue,
|
|
48759
|
+
trajectoryValue,
|
|
48760
|
+
setTrajectoryValue,
|
|
46725
48761
|
validationErrors,
|
|
46726
48762
|
onSave,
|
|
46727
48763
|
onCancel,
|
|
@@ -46751,6 +48787,18 @@ function EditModeContent({
|
|
|
46751
48787
|
),
|
|
46752
48788
|
validationErrors?.field === "groundTruth" && /* @__PURE__ */ jsxRuntime.jsx(ValidationErrors$1, { field: "groundTruth", errors: validationErrors.errors })
|
|
46753
48789
|
] }),
|
|
48790
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
48791
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Expected Trajectory (JSON, optional)" }),
|
|
48792
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
48793
|
+
CodeEditor,
|
|
48794
|
+
{
|
|
48795
|
+
value: trajectoryValue,
|
|
48796
|
+
onChange: setTrajectoryValue,
|
|
48797
|
+
showCopyButton: false,
|
|
48798
|
+
className: "min-h-[80px]"
|
|
48799
|
+
}
|
|
48800
|
+
)
|
|
48801
|
+
] }),
|
|
46754
48802
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
46755
48803
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Metadata (JSON, optional)" }),
|
|
46756
48804
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -46968,6 +49016,7 @@ function DatasetItemPanel({ datasetId, item, items, onItemChange, onClose }) {
|
|
|
46968
49016
|
const [inputValue, setInputValue] = React.useState("");
|
|
46969
49017
|
const [groundTruthValue, setGroundTruthValue] = React.useState("");
|
|
46970
49018
|
const [metadataValue, setMetadataValue] = React.useState("");
|
|
49019
|
+
const [trajectoryValue, setTrajectoryValue] = React.useState("");
|
|
46971
49020
|
const [validationErrors, setValidationErrors] = React.useState(null);
|
|
46972
49021
|
const [showDeleteConfirm, setShowDeleteConfirm] = React.useState(false);
|
|
46973
49022
|
React.useEffect(() => {
|
|
@@ -46975,6 +49024,7 @@ function DatasetItemPanel({ datasetId, item, items, onItemChange, onClose }) {
|
|
|
46975
49024
|
setInputValue(JSON.stringify(item.input, null, 2));
|
|
46976
49025
|
setGroundTruthValue(item.groundTruth ? JSON.stringify(item.groundTruth, null, 2) : "");
|
|
46977
49026
|
setMetadataValue(item.metadata ? JSON.stringify(item.metadata, null, 2) : "");
|
|
49027
|
+
setTrajectoryValue(item.expectedTrajectory ? JSON.stringify(item.expectedTrajectory, null, 2) : "");
|
|
46978
49028
|
setIsEditing(false);
|
|
46979
49029
|
setShowDeleteConfirm(false);
|
|
46980
49030
|
setValidationErrors(null);
|
|
@@ -47020,13 +49070,23 @@ function DatasetItemPanel({ datasetId, item, items, onItemChange, onClose }) {
|
|
|
47020
49070
|
return;
|
|
47021
49071
|
}
|
|
47022
49072
|
}
|
|
49073
|
+
let parsedTrajectory = null;
|
|
49074
|
+
if (trajectoryValue.trim()) {
|
|
49075
|
+
try {
|
|
49076
|
+
parsedTrajectory = JSON.parse(trajectoryValue);
|
|
49077
|
+
} catch {
|
|
49078
|
+
toast.error("Expected Trajectory must be valid JSON");
|
|
49079
|
+
return;
|
|
49080
|
+
}
|
|
49081
|
+
}
|
|
47023
49082
|
try {
|
|
47024
49083
|
await updateItem.mutateAsync({
|
|
47025
49084
|
datasetId,
|
|
47026
49085
|
itemId: item.id,
|
|
47027
49086
|
input: parsedInput,
|
|
47028
49087
|
groundTruth: parsedGroundTruth,
|
|
47029
|
-
metadata: parsedMetadata
|
|
49088
|
+
metadata: parsedMetadata,
|
|
49089
|
+
expectedTrajectory: parsedTrajectory
|
|
47030
49090
|
});
|
|
47031
49091
|
toast.success("Item updated successfully");
|
|
47032
49092
|
setIsEditing(false);
|
|
@@ -47044,6 +49104,7 @@ function DatasetItemPanel({ datasetId, item, items, onItemChange, onClose }) {
|
|
|
47044
49104
|
setInputValue(JSON.stringify(item.input, null, 2));
|
|
47045
49105
|
setGroundTruthValue(item.groundTruth ? JSON.stringify(item.groundTruth, null, 2) : "");
|
|
47046
49106
|
setMetadataValue(item.metadata ? JSON.stringify(item.metadata, null, 2) : "");
|
|
49107
|
+
setTrajectoryValue(item.expectedTrajectory ? JSON.stringify(item.expectedTrajectory, null, 2) : "");
|
|
47047
49108
|
setIsEditing(false);
|
|
47048
49109
|
setValidationErrors(null);
|
|
47049
49110
|
};
|
|
@@ -47099,6 +49160,8 @@ function DatasetItemPanel({ datasetId, item, items, onItemChange, onClose }) {
|
|
|
47099
49160
|
setGroundTruthValue: handleGroundTruthValueChange,
|
|
47100
49161
|
metadataValue,
|
|
47101
49162
|
setMetadataValue,
|
|
49163
|
+
trajectoryValue,
|
|
49164
|
+
setTrajectoryValue,
|
|
47102
49165
|
validationErrors,
|
|
47103
49166
|
onSave: handleSave,
|
|
47104
49167
|
onCancel: handleCancel,
|
|
@@ -47226,6 +49289,7 @@ function DatasetItemsList({
|
|
|
47226
49289
|
/* @__PURE__ */ jsxRuntime.jsx(ItemList.IdCell, { id: listItem.id }),
|
|
47227
49290
|
/* @__PURE__ */ jsxRuntime.jsx(ItemList.TextCell, { className: "font-mono", children: listItem.input }),
|
|
47228
49291
|
columns.some((col) => col.name === "groundTruth") && /* @__PURE__ */ jsxRuntime.jsx(ItemList.TextCell, { className: "font-mono", children: listItem.groundTruth }),
|
|
49292
|
+
columns.some((col) => col.name === "trajectory") && /* @__PURE__ */ jsxRuntime.jsx(ItemList.TextCell, { children: item.expectedTrajectory ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: Array.isArray(item.expectedTrajectory?.steps) ? `${item.expectedTrajectory.steps.length} steps` : "Yes" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral4", children: "—" }) }),
|
|
47229
49293
|
/* @__PURE__ */ jsxRuntime.jsx(ItemList.DateCell, { date: listItem.date, withTime: true })
|
|
47230
49294
|
]
|
|
47231
49295
|
}
|
|
@@ -47689,6 +49753,7 @@ function DatasetItems({
|
|
|
47689
49753
|
{ name: "id", label: "ID", size: "5rem" },
|
|
47690
49754
|
{ name: "input", label: "Input", size: "1fr" },
|
|
47691
49755
|
...!featuredItem ? [{ name: "groundTruth", label: "Ground Truth", size: "1fr" }] : [],
|
|
49756
|
+
...!featuredItem ? [{ name: "trajectory", label: "Trajectory", size: "6rem" }] : [],
|
|
47692
49757
|
{ name: "date", label: "Created", size: "10rem" }
|
|
47693
49758
|
];
|
|
47694
49759
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -49155,6 +51220,7 @@ function ValidationErrors({ field, errors }) {
|
|
|
49155
51220
|
function AddItemDialog({ datasetId, open, onOpenChange, onSuccess }) {
|
|
49156
51221
|
const [input, setInput] = React.useState("{}");
|
|
49157
51222
|
const [groundTruth, setGroundTruth] = React.useState("");
|
|
51223
|
+
const [expectedTrajectory, setExpectedTrajectory] = React.useState("");
|
|
49158
51224
|
const [validationErrors, setValidationErrors] = React.useState(null);
|
|
49159
51225
|
const { addItem } = useDatasetMutations();
|
|
49160
51226
|
const handleSubmit = async (e) => {
|
|
@@ -49175,16 +51241,27 @@ function AddItemDialog({ datasetId, open, onOpenChange, onSuccess }) {
|
|
|
49175
51241
|
return;
|
|
49176
51242
|
}
|
|
49177
51243
|
}
|
|
51244
|
+
let parsedTrajectory;
|
|
51245
|
+
if (expectedTrajectory.trim()) {
|
|
51246
|
+
try {
|
|
51247
|
+
parsedTrajectory = JSON.parse(expectedTrajectory);
|
|
51248
|
+
} catch {
|
|
51249
|
+
toast.error("Expected Trajectory must be valid JSON");
|
|
51250
|
+
return;
|
|
51251
|
+
}
|
|
51252
|
+
}
|
|
49178
51253
|
try {
|
|
49179
51254
|
await addItem.mutateAsync({
|
|
49180
51255
|
datasetId,
|
|
49181
51256
|
input: parsedInput,
|
|
49182
|
-
groundTruth: parsedGroundTruth
|
|
51257
|
+
groundTruth: parsedGroundTruth,
|
|
51258
|
+
expectedTrajectory: parsedTrajectory
|
|
49183
51259
|
});
|
|
49184
51260
|
toast.success("Item added successfully");
|
|
49185
51261
|
setValidationErrors(null);
|
|
49186
51262
|
setInput("{}");
|
|
49187
51263
|
setGroundTruth("");
|
|
51264
|
+
setExpectedTrajectory("");
|
|
49188
51265
|
onOpenChange(false);
|
|
49189
51266
|
onSuccess?.();
|
|
49190
51267
|
} catch (error) {
|
|
@@ -49211,6 +51288,7 @@ function AddItemDialog({ datasetId, open, onOpenChange, onSuccess }) {
|
|
|
49211
51288
|
const handleCancel = () => {
|
|
49212
51289
|
setInput("{}");
|
|
49213
51290
|
setGroundTruth("");
|
|
51291
|
+
setExpectedTrajectory("");
|
|
49214
51292
|
setValidationErrors(null);
|
|
49215
51293
|
onOpenChange(false);
|
|
49216
51294
|
};
|
|
@@ -49235,6 +51313,18 @@ function AddItemDialog({ datasetId, open, onOpenChange, onSuccess }) {
|
|
|
49235
51313
|
),
|
|
49236
51314
|
validationErrors?.field === "groundTruth" && /* @__PURE__ */ jsxRuntime.jsx(ValidationErrors, { field: "groundTruth", errors: validationErrors.errors })
|
|
49237
51315
|
] }),
|
|
51316
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
51317
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "item-trajectory", children: "Expected Trajectory (JSON, optional)" }),
|
|
51318
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
51319
|
+
CodeEditor,
|
|
51320
|
+
{
|
|
51321
|
+
value: expectedTrajectory,
|
|
51322
|
+
onChange: setExpectedTrajectory,
|
|
51323
|
+
showCopyButton: false,
|
|
51324
|
+
className: "min-h-[80px]"
|
|
51325
|
+
}
|
|
51326
|
+
)
|
|
51327
|
+
] }),
|
|
49238
51328
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 pt-4", children: [
|
|
49239
51329
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "button", onClick: handleCancel, children: "Cancel" }),
|
|
49240
51330
|
/* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", variant: "primary", disabled: addItem.isPending, children: addItem.isPending ? "Adding..." : "Add Item" })
|
|
@@ -53723,72 +55813,6 @@ function EvaluationDatasetsList({
|
|
|
53723
55813
|
] });
|
|
53724
55814
|
}
|
|
53725
55815
|
|
|
53726
|
-
const statusBadgeVariants = cva(
|
|
53727
|
-
// Base styles
|
|
53728
|
-
"inline-flex items-center gap-1.5 rounded-full text-ui-xs font-medium transition-colors duration-normal",
|
|
53729
|
-
{
|
|
53730
|
-
variants: {
|
|
53731
|
-
variant: {
|
|
53732
|
-
success: "bg-accent1Dark text-accent1",
|
|
53733
|
-
warning: "bg-accent6Dark text-accent6",
|
|
53734
|
-
error: "bg-accent2Dark text-accent2",
|
|
53735
|
-
info: "bg-accent5Dark text-accent5",
|
|
53736
|
-
neutral: "bg-surface4 text-neutral4"
|
|
53737
|
-
},
|
|
53738
|
-
size: {
|
|
53739
|
-
sm: "px-1.5 py-0.5 text-ui-xs",
|
|
53740
|
-
md: "px-2 py-1 text-ui-xs",
|
|
53741
|
-
lg: "px-2.5 py-1 text-ui-sm"
|
|
53742
|
-
},
|
|
53743
|
-
withDot: {
|
|
53744
|
-
true: "",
|
|
53745
|
-
false: ""
|
|
53746
|
-
},
|
|
53747
|
-
pulse: {
|
|
53748
|
-
true: "",
|
|
53749
|
-
false: ""
|
|
53750
|
-
}
|
|
53751
|
-
},
|
|
53752
|
-
defaultVariants: {
|
|
53753
|
-
variant: "neutral",
|
|
53754
|
-
size: "md",
|
|
53755
|
-
withDot: false,
|
|
53756
|
-
pulse: false
|
|
53757
|
-
}
|
|
53758
|
-
}
|
|
53759
|
-
);
|
|
53760
|
-
const dotVariants = cva("rounded-full", {
|
|
53761
|
-
variants: {
|
|
53762
|
-
variant: {
|
|
53763
|
-
success: "bg-accent1",
|
|
53764
|
-
warning: "bg-accent6",
|
|
53765
|
-
error: "bg-accent2",
|
|
53766
|
-
info: "bg-accent5",
|
|
53767
|
-
neutral: "bg-neutral3"
|
|
53768
|
-
},
|
|
53769
|
-
size: {
|
|
53770
|
-
sm: "w-1 h-1",
|
|
53771
|
-
md: "w-1.5 h-1.5",
|
|
53772
|
-
lg: "w-2 h-2"
|
|
53773
|
-
},
|
|
53774
|
-
pulse: {
|
|
53775
|
-
true: "animate-pulse",
|
|
53776
|
-
false: ""
|
|
53777
|
-
}
|
|
53778
|
-
},
|
|
53779
|
-
defaultVariants: {
|
|
53780
|
-
variant: "neutral",
|
|
53781
|
-
size: "md",
|
|
53782
|
-
pulse: false
|
|
53783
|
-
}
|
|
53784
|
-
});
|
|
53785
|
-
function StatusBadge({ className, variant, size, withDot, pulse, children, ...props }) {
|
|
53786
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: cn(statusBadgeVariants({ variant, size, withDot, pulse }), className), ...props, children: [
|
|
53787
|
-
withDot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: dotVariants({ variant, size, pulse }) }),
|
|
53788
|
-
children
|
|
53789
|
-
] });
|
|
53790
|
-
}
|
|
53791
|
-
|
|
53792
55816
|
const COLUMNS$1 = "auto 1fr auto auto auto auto auto auto auto";
|
|
53793
55817
|
function formatDate(dateStr) {
|
|
53794
55818
|
if (!dateStr) return "—";
|
|
@@ -54175,8 +56199,12 @@ function EvaluationScorersList({ scorers, isLoading, error }) {
|
|
|
54175
56199
|
const description = scorer.scorer.config?.description || "";
|
|
54176
56200
|
const agentCount = scorer.agentIds?.length ?? 0;
|
|
54177
56201
|
const workflowCount = scorer.workflowIds?.length ?? 0;
|
|
56202
|
+
const isTrajectory = scorer.scorer.config?.type === "trajectory";
|
|
54178
56203
|
return /* @__PURE__ */ jsxRuntime.jsxs(EntityList.RowLink, { to: paths.scorerLink(scorer.id), children: [
|
|
54179
|
-
/* @__PURE__ */ jsxRuntime.jsx(EntityList.NameCell, { children:
|
|
56204
|
+
/* @__PURE__ */ jsxRuntime.jsx(EntityList.NameCell, { children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
56205
|
+
name,
|
|
56206
|
+
isTrajectory && /* @__PURE__ */ jsxRuntime.jsx(Chip, { size: "small", color: "purple", children: "trajectory" })
|
|
56207
|
+
] }) }),
|
|
54180
56208
|
/* @__PURE__ */ jsxRuntime.jsx(EntityList.DescriptionCell, { children: description }),
|
|
54181
56209
|
/* @__PURE__ */ jsxRuntime.jsx(EntityList.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: scorer.source === "code" ? "info" : "default", children: scorer.source }) }),
|
|
54182
56210
|
/* @__PURE__ */ jsxRuntime.jsx(EntityList.TextCell, { className: "text-center", children: agentCount || "" }),
|
|
@@ -57757,6 +59785,15 @@ exports.Avatar = Avatar;
|
|
|
57757
59785
|
exports.Badge = Badge;
|
|
57758
59786
|
exports.BranchIcon = BranchIcon;
|
|
57759
59787
|
exports.Breadcrumb = Breadcrumb$1;
|
|
59788
|
+
exports.BrowserSessionProvider = BrowserSessionProvider;
|
|
59789
|
+
exports.BrowserSidebarTab = BrowserSidebarTab;
|
|
59790
|
+
exports.BrowserThumbnail = BrowserThumbnail;
|
|
59791
|
+
exports.BrowserToolCallHistory = BrowserToolCallHistory;
|
|
59792
|
+
exports.BrowserToolCallItem = BrowserToolCallItem;
|
|
59793
|
+
exports.BrowserToolCallsProvider = BrowserToolCallsProvider;
|
|
59794
|
+
exports.BrowserViewFrame = BrowserViewFrame;
|
|
59795
|
+
exports.BrowserViewHeader = BrowserViewHeader;
|
|
59796
|
+
exports.BrowserViewPanel = BrowserViewPanel;
|
|
57760
59797
|
exports.Button = Button;
|
|
57761
59798
|
exports.ButtonWithTooltip = ButtonWithTooltip;
|
|
57762
59799
|
exports.ButtonsGroup = ButtonsGroup;
|
|
@@ -58209,6 +60246,8 @@ exports.highlight = highlight;
|
|
|
58209
60246
|
exports.inputVariants = inputVariants;
|
|
58210
60247
|
exports.isActive = isActive;
|
|
58211
60248
|
exports.isAuthenticated = isAuthenticated;
|
|
60249
|
+
exports.isBrowserTool = isBrowserTool;
|
|
60250
|
+
exports.isBrowserToolError = isBrowserToolError;
|
|
58212
60251
|
exports.isRule = isRule;
|
|
58213
60252
|
exports.isRuleGroup = isRuleGroup;
|
|
58214
60253
|
exports.isValidLogsDatePreset = isValidLogsDatePreset;
|
|
@@ -58267,6 +60306,10 @@ exports.useAllIntegrationTools = useAllIntegrationTools;
|
|
|
58267
60306
|
exports.useAllModels = useAllModels;
|
|
58268
60307
|
exports.useAuthCapabilities = useAuthCapabilities;
|
|
58269
60308
|
exports.useAvgScoreKpiMetrics = useAvgScoreKpiMetrics;
|
|
60309
|
+
exports.useBrowserSession = useBrowserSession;
|
|
60310
|
+
exports.useBrowserStream = useBrowserStream;
|
|
60311
|
+
exports.useBrowserToolCalls = useBrowserToolCalls;
|
|
60312
|
+
exports.useBrowserToolCallsSafe = useBrowserToolCallsSafe;
|
|
58270
60313
|
exports.useCSVParser = useCSVParser;
|
|
58271
60314
|
exports.useCanCreateAgent = useCanCreateAgent;
|
|
58272
60315
|
exports.useCloneThread = useCloneThread;
|