From 1e97c58d4f0943bfe7e8ffba6ffe6f9f7daa8b43 Mon Sep 17 00:00:00 2001 From: Stanislav Novosad Date: Fri, 5 Dec 2025 15:44:12 -0700 Subject: [PATCH] SDK: log url when running tasks (#4189) --- skyvern/library/skyvern.py | 45 ++++++++++++++++++++++--- skyvern/library/skyvern_browser_page.py | 23 ++++++++++--- 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/skyvern/library/skyvern.py b/skyvern/library/skyvern.py index bf7d10ba..fa0ad6ab 100644 --- a/skyvern/library/skyvern.py +++ b/skyvern/library/skyvern.py @@ -22,6 +22,10 @@ from skyvern.schemas.runs import ProxyLocation, RunEngine, RunStatus LOG = structlog.get_logger() +def _get_browser_session_url(browser_session_id: str) -> str: + return f"https://app.skyvern.com/browser-session/{browser_session_id}" + + class Skyvern(AsyncSkyvern): """Main entry point for the Skyvern SDK. @@ -213,6 +217,11 @@ class Skyvern(AsyncSkyvern): return obj + @property + def environment(self) -> SkyvernEnvironment | None: + """Get the current Skyvern environment (CLOUD, STAGING, LOCAL, or None for embedded mode).""" + return self._environment + async def run_task( self, prompt: str, @@ -453,7 +462,15 @@ class Skyvern(AsyncSkyvern): """ self._ensure_cloud_environment() browser_session = await self.get_browser_session(browser_session_id) - LOG.info("Connecting to existing cloud browser session", browser_session_id=browser_session.browser_session_id) + if self._environment == SkyvernEnvironment.CLOUD: + LOG.info( + "Connecting to existing cloud browser session", + url=_get_browser_session_url(browser_session.browser_session_id), + ) + else: + LOG.info( + "Connecting to existing cloud browser session", browser_session_id=browser_session.browser_session_id + ) return await self._connect_to_cloud_browser_session(browser_session) async def launch_cloud_browser( @@ -480,7 +497,13 @@ class Skyvern(AsyncSkyvern): timeout=timeout, proxy_location=proxy_location, ) - LOG.info("Launched new cloud browser session", browser_session_id=browser_session.browser_session_id) + if self._environment == SkyvernEnvironment.CLOUD: + LOG.info( + "Launched new cloud browser session", + url=_get_browser_session_url(browser_session.browser_session_id), + ) + else: + LOG.info("Launched new cloud browser session", browser_session_id=browser_session.browser_session_id) return await self._connect_to_cloud_browser_session(browser_session) async def use_cloud_browser( @@ -515,9 +538,23 @@ class Skyvern(AsyncSkyvern): timeout=timeout, proxy_location=proxy_location, ) - LOG.info("Launched new cloud browser session", browser_session_id=browser_session.browser_session_id) + if self._environment == SkyvernEnvironment.CLOUD: + LOG.info( + "Launched new cloud browser session", + url=_get_browser_session_url(browser_session.browser_session_id), + ) + else: + LOG.info("Launched new cloud browser session", browser_session_id=browser_session.browser_session_id) else: - LOG.info("Reusing existing cloud browser session", browser_session_id=browser_session.browser_session_id) + if self._environment == SkyvernEnvironment.CLOUD: + LOG.info( + "Reusing existing cloud browser session", + url=_get_browser_session_url(browser_session.browser_session_id), + ) + else: + LOG.info( + "Reusing existing cloud browser session", browser_session_id=browser_session.browser_session_id + ) return await self._connect_to_cloud_browser_session(browser_session) diff --git a/skyvern/library/skyvern_browser_page.py b/skyvern/library/skyvern_browser_page.py index ee80f7d1..725b3666 100644 --- a/skyvern/library/skyvern_browser_page.py +++ b/skyvern/library/skyvern_browser_page.py @@ -4,7 +4,7 @@ from typing import TYPE_CHECKING, Any import structlog from playwright.async_api import Page -from skyvern.client import GetRunResponse +from skyvern.client import GetRunResponse, SkyvernEnvironment from skyvern.client.core import RequestOptions from skyvern.client.types.workflow_run_response import WorkflowRunResponse from skyvern.core.script_generations.skyvern_page import SkyvernPage @@ -20,6 +20,10 @@ from skyvern.schemas.runs import RunEngine, RunStatus, TaskRunResponse LOG = structlog.get_logger() +def _get_app_url_for_run(run_id: str) -> str: + return f"https://app.skyvern.com/runs/{run_id}" + + class SkyvernPageRun: """Provides methods to run Skyvern tasks and workflows in the context of a browser page. @@ -88,7 +92,10 @@ class SkyvernPageRun: user_agent=user_agent, request_options=RequestOptions(additional_headers={"X-User-Agent": "skyvern-sdk"}), ) - LOG.info("AI task is running, this may take a while", run_id=task_run.run_id) + if self._browser.skyvern.environment == SkyvernEnvironment.CLOUD: + LOG.info("AI task is running, this may take a while", url=_get_app_url_for_run(task_run.run_id)) + else: + LOG.info("AI task is running, this may take a while", run_id=task_run.run_id) task_run = await self._wait_for_run_completion(task_run.run_id, timeout) LOG.info("AI task finished", run_id=task_run.run_id, status=task_run.status) @@ -151,7 +158,12 @@ class SkyvernPageRun: extra_http_headers=extra_http_headers, request_options=RequestOptions(additional_headers={"X-User-Agent": "skyvern-sdk"}), ) - LOG.info("AI login workflow is running, this may take a while", run_id=workflow_run.run_id) + if self._browser.skyvern.environment == SkyvernEnvironment.CLOUD: + LOG.info( + "AI login workflow is running, this may take a while", url=_get_app_url_for_run(workflow_run.run_id) + ) + else: + LOG.info("AI login workflow is running, this may take a while", run_id=workflow_run.run_id) workflow_run = await self._wait_for_run_completion(workflow_run.run_id, timeout) LOG.info("AI login workflow finished", run_id=workflow_run.run_id, status=workflow_run.status) @@ -252,7 +264,10 @@ class SkyvernPageRun: browser_address=self._browser.browser_address, request_options=RequestOptions(additional_headers={"X-User-Agent": "skyvern-sdk"}), ) - LOG.info("AI workflow is running, this may take a while", run_id=workflow_run.run_id) + if self._browser.skyvern.environment == SkyvernEnvironment.CLOUD: + LOG.info("AI workflow is running, this may take a while", url=_get_app_url_for_run(workflow_run.run_id)) + else: + LOG.info("AI workflow is running, this may take a while", run_id=workflow_run.run_id) workflow_run = await self._wait_for_run_completion(workflow_run.run_id, timeout) LOG.info("AI workflow finished", run_id=workflow_run.run_id, status=workflow_run.status)