diff --git a/skyvern/config.py b/skyvern/config.py index a32fee06..cfa11610 100644 --- a/skyvern/config.py +++ b/skyvern/config.py @@ -257,6 +257,7 @@ class Settings(BaseSettings): TASK_BLOCKED_SITE_FALLBACK_URL: str = "https://www.google.com" + SKYVERN_APP_URL: str = "http://localhost:8080" # SkyvernClient Settings SKYVERN_BASE_URL: str = "https://api.skyvern.com" SKYVERN_API_KEY: str = "PLACEHOLDER" diff --git a/skyvern/forge/sdk/routes/agent_protocol.py b/skyvern/forge/sdk/routes/agent_protocol.py index f11a5d34..2b0ac1b8 100644 --- a/skyvern/forge/sdk/routes/agent_protocol.py +++ b/skyvern/forge/sdk/routes/agent_protocol.py @@ -1523,6 +1523,7 @@ async def run_task( failure_reason=task_v1_response.failure_reason, created_at=task_v1_response.created_at, modified_at=task_v1_response.modified_at, + app_url=f"{settings.SKYVERN_APP_URL.rstrip('/')}/tasks/{task_v1_response.task_id}", run_request=TaskRunRequest( engine=run_request.engine, prompt=task_v1_response.navigation_goal, @@ -1566,6 +1567,10 @@ async def run_task( max_steps_override=run_request.max_steps, browser_session_id=run_request.browser_session_id, ) + refreshed_task_v2 = await app.DATABASE.get_task_v2( + task_v2_id=task_v2.observer_cruise_id, organization_id=current_org.organization_id + ) + task_v2 = refreshed_task_v2 if refreshed_task_v2 else task_v2 return TaskRunResponse( run_id=task_v2.observer_cruise_id, run_type=RunType.task_v2, @@ -1574,6 +1579,7 @@ async def run_task( failure_reason=None, created_at=task_v2.created_at, modified_at=task_v2.modified_at, + app_url=f"{settings.SKYVERN_APP_URL.rstrip('/')}/{task_v2.workflow_permanent_id}/{task_v2.workflow_run_id}", run_request=TaskRunRequest( engine=RunEngine.skyvern_v2, prompt=task_v2.prompt, diff --git a/skyvern/schemas/runs.py b/skyvern/schemas/runs.py index fb1c0ea1..02a8bb21 100644 --- a/skyvern/schemas/runs.py +++ b/skyvern/schemas/runs.py @@ -286,6 +286,7 @@ class BaseRunResponse(BaseModel): failure_reason: str | None = Field(default=None, description="Reason for failure if the run failed") created_at: datetime = Field(description="Timestamp when this run was created") modified_at: datetime = Field(description="Timestamp when this run was last modified") + app_url: str | None = Field(default=None, description="URL to the application UI where the run can be viewed") class TaskRunResponse(BaseRunResponse): diff --git a/skyvern/services/run_service.py b/skyvern/services/run_service.py index 487751c8..4c29043b 100644 --- a/skyvern/services/run_service.py +++ b/skyvern/services/run_service.py @@ -1,5 +1,6 @@ from fastapi import HTTPException, status +from skyvern.config import settings from skyvern.exceptions import TaskNotFound, WorkflowRunNotFound from skyvern.forge import app from skyvern.forge.sdk.schemas.tasks import TaskStatus @@ -35,6 +36,7 @@ async def get_run_response(run_id: str, organization_id: str | None = None) -> R failure_reason=task_v1.failure_reason, created_at=task_v1.created_at, modified_at=task_v1.modified_at, + app_url=f"{settings.SKYVERN_APP_URL.rstrip('/')}/tasks/{task_v1.task_id}", run_request=TaskRunRequest( engine=run_engine, prompt=task_v1.navigation_goal, @@ -63,6 +65,7 @@ async def get_run_response(run_id: str, organization_id: str | None = None) -> R failure_reason=workflow_run.failure_reason if workflow_run else None, created_at=task_v2.created_at, modified_at=task_v2.modified_at, + app_url=f"{settings.SKYVERN_APP_URL.rstrip('/')}/{task_v2.workflow_permanent_id}/{task_v2.workflow_run_id}", run_request=TaskRunRequest( engine=RunEngine.skyvern_v2, prompt=task_v2.prompt,