From 6f6e83727067bb81e8a148a22a4a208425735835 Mon Sep 17 00:00:00 2001 From: Shuchang Zheng Date: Tue, 20 Jan 2026 09:21:30 -0800 Subject: [PATCH] enable VNC streaming for task v1 page (#4498) --- skyvern-frontend/src/api/types.ts | 1 + .../src/routes/tasks/detail/TaskActions.tsx | 39 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/skyvern-frontend/src/api/types.ts b/skyvern-frontend/src/api/types.ts index df9a3357..eb5074ac 100644 --- a/skyvern-frontend/src/api/types.ts +++ b/skyvern-frontend/src/api/types.ts @@ -150,6 +150,7 @@ export type TaskApiResponse = { max_steps_per_run: number | null; task_v2: TaskV2 | null; workflow_run_id: string | null; + browser_session_id: string | null; }; export type CreateTaskRequest = { diff --git a/skyvern-frontend/src/routes/tasks/detail/TaskActions.tsx b/skyvern-frontend/src/routes/tasks/detail/TaskActions.tsx index 329ea807..57349b52 100644 --- a/skyvern-frontend/src/routes/tasks/detail/TaskActions.tsx +++ b/skyvern-frontend/src/routes/tasks/detail/TaskActions.tsx @@ -1,5 +1,7 @@ import { getClient } from "@/api/AxiosClient"; import { Status, StepApiResponse, TaskApiResponse } from "@/api/types"; +import { BrowserStream } from "@/components/BrowserStream"; +import { AspectRatio } from "@/components/ui/aspect-ratio"; import { Skeleton } from "@/components/ui/skeleton"; import { toast } from "@/components/ui/use-toast"; import { ZoomableImage } from "@/components/ZoomableImage"; @@ -66,8 +68,14 @@ function TaskActions() { }); const taskIsNotFinalized = task && statusIsNotFinalized(task); const taskIsRunningOrQueued = task && statusIsRunningOrQueued(task); + const browserSessionId = task?.browser_session_id; useEffect(() => { + // Skip screenshot WebSocket if VNC streaming is available via browser_session_id + if (browserSessionId) { + return; + } + if (!taskIsRunningOrQueued) { return; } @@ -138,7 +146,13 @@ function TaskActions() { socket = null; } }; - }, [credentialGetter, taskId, taskIsRunningOrQueued, queryClient]); + }, [ + browserSessionId, + credentialGetter, + taskId, + taskIsRunningOrQueued, + queryClient, + ]); const { data: steps, isLoading: stepsIsLoading } = useQuery< Array @@ -192,6 +206,29 @@ function TaskActions() { activeSelection !== "stream" ? actions[activeSelection] : null; function getStream() { + // Use VNC streaming via BrowserStream when browser_session_id is available + if (browserSessionId) { + return ( + + { + queryClient.invalidateQueries({ + queryKey: ["task", taskId], + }); + queryClient.invalidateQueries({ + queryKey: ["tasks"], + }); + }} + /> + + ); + } + + // Fall back to screenshot-based streaming if (task?.status === Status.Created) { return (