diff --git a/skyvern/forge/agent.py b/skyvern/forge/agent.py index 1c00d482..8d68bec6 100644 --- a/skyvern/forge/agent.py +++ b/skyvern/forge/agent.py @@ -3577,6 +3577,7 @@ class ForgeAgent: video_artifacts = await app.BROWSER_MANAGER.get_video_artifacts( task_id=task.task_id, browser_state=browser_state ) + LOG.debug("Uploading video artifacts", number_of_video_artifacts=len(video_artifacts)) for video_artifact in video_artifacts: await app.ARTIFACT_MANAGER.update_artifact_data( artifact_id=video_artifact.video_artifact_id, @@ -3585,6 +3586,7 @@ class ForgeAgent: ) har_data = await app.BROWSER_MANAGER.get_har_data(task_id=task.task_id, browser_state=browser_state) + LOG.debug("Uploading har data", har_size=len(har_data)) if har_data: await app.ARTIFACT_MANAGER.create_artifact( step=last_step, @@ -3595,6 +3597,7 @@ class ForgeAgent: browser_log = await app.BROWSER_MANAGER.get_browser_console_log( task_id=task.task_id, browser_state=browser_state ) + LOG.debug("Uploading browser log", browser_log_size=len(browser_log)) if browser_log: await app.ARTIFACT_MANAGER.create_artifact( step=last_step, diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index 243587fd..20ebde92 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -3245,6 +3245,7 @@ class WorkflowService: workflow_run_id=workflow_run.workflow_run_id, browser_state=browser_state, ) + LOG.debug("Persisting video data", number_of_video_artifacts=len(video_artifacts)) for video_artifact in video_artifacts: await app.ARTIFACT_MANAGER.update_artifact_data( artifact_id=video_artifact.video_artifact_id, @@ -3264,6 +3265,7 @@ class WorkflowService: workflow_run_id=workflow_run.workflow_run_id, browser_state=browser_state, ) + LOG.debug("Persisting har data", har_size=len(har_data)) if har_data: await app.ARTIFACT_MANAGER.create_artifact( step=last_step, @@ -3283,6 +3285,7 @@ class WorkflowService: workflow_run_id=workflow_run.workflow_run_id, browser_state=browser_state, ) + LOG.debug("Persisting browser log", browser_log_size=len(browser_log)) if browser_log: await app.ARTIFACT_MANAGER.create_artifact( step=last_step, diff --git a/skyvern/webeye/browser_artifacts.py b/skyvern/webeye/browser_artifacts.py index 1b4ebb7b..a49e7123 100644 --- a/skyvern/webeye/browser_artifacts.py +++ b/skyvern/webeye/browser_artifacts.py @@ -4,8 +4,11 @@ import asyncio import os import aiofiles +import structlog from pydantic import BaseModel, PrivateAttr +LOG = structlog.get_logger() + class VideoArtifact(BaseModel): video_path: str | None = None @@ -29,13 +32,26 @@ class BrowserArtifacts(BaseModel): async with aiofiles.open(self.browser_console_log_path, "a") as f: return await f.write(msg) - async def read_browser_console_log(self) -> bytes: + async def _read_console_log_file(self) -> bytes: if self.browser_console_log_path is None: return b"" - async with self._browser_console_log_lock: - if not os.path.exists(self.browser_console_log_path): - return b"" + if not os.path.exists(self.browser_console_log_path): + return b"" + async with aiofiles.open(self.browser_console_log_path, "rb") as f: + return await f.read() - async with aiofiles.open(self.browser_console_log_path, "rb") as f: - return await f.read() + async def read_browser_console_log(self, timeout: float = 5) -> bytes: + if self.browser_console_log_path is None: + return b"" + + try: + async with asyncio.timeout(timeout): + async with self._browser_console_log_lock: + return await self._read_console_log_file() + except asyncio.TimeoutError: + LOG.warning( + "Failed to acquire browser console log lock, reading file without lock (may be incomplete)", + timeout=timeout, + ) + return await self._read_console_log_file() diff --git a/skyvern/webeye/real_browser_manager.py b/skyvern/webeye/real_browser_manager.py index 11731fd5..1f6f5947 100644 --- a/skyvern/webeye/real_browser_manager.py +++ b/skyvern/webeye/real_browser_manager.py @@ -264,6 +264,14 @@ class RealBrowserManager(BrowserManager): if path and os.path.exists(path=path): with open(path, "rb") as f: browser_state.browser_artifacts.video_artifacts[i].video_data = f.read() + else: + LOG.debug( + "Video path not found", + task_id=task_id, + workflow_id=workflow_id, + workflow_run_id=workflow_run_id, + video_path=path, + ) return browser_state.browser_artifacts.video_artifacts