From 343894d7a4b92b6a12cc912161fef0aaca2b7757 Mon Sep 17 00:00:00 2001 From: Shuchang Zheng Date: Fri, 16 May 2025 16:11:22 -0700 Subject: [PATCH] API documentation update - Part 1 (#2366) --- skyvern/forge/sdk/routes/agent_protocol.py | 53 ++++++++++++++---- .../forge/sdk/services/org_auth_service.py | 5 +- skyvern/schemas/runs.py | 54 +++++++++++++------ 3 files changed, 83 insertions(+), 29 deletions(-) diff --git a/skyvern/forge/sdk/routes/agent_protocol.py b/skyvern/forge/sdk/routes/agent_protocol.py index 21f0590b..36f227d4 100644 --- a/skyvern/forge/sdk/routes/agent_protocol.py +++ b/skyvern/forge/sdk/routes/agent_protocol.py @@ -179,7 +179,10 @@ async def run_task_v1( background_tasks: BackgroundTasks, task: TaskRequest, current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, x_max_steps_override: Annotated[int | None, Header()] = None, x_user_agent: Annotated[str | None, Header()] = None, ) -> CreateTaskResponse: @@ -227,7 +230,10 @@ async def get_task_v1( async def cancel_task( task_id: str, current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, ) -> None: analytics.capture("skyvern-oss-agent-task-get") task_obj = await app.DATABASE.get_task(task_id, organization_id=current_org.organization_id) @@ -255,7 +261,10 @@ async def cancel_task( async def cancel_workflow_run( workflow_run_id: str, current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, ) -> None: workflow_run = await app.DATABASE.get_workflow_run( workflow_run_id=workflow_run_id, @@ -300,7 +309,10 @@ async def cancel_workflow_run( async def retry_webhook( task_id: str, current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, ) -> TaskResponse: analytics.capture("skyvern-oss-agent-task-retry-webhook") task_obj = await app.DATABASE.get_task(task_id, organization_id=current_org.organization_id) @@ -429,7 +441,9 @@ async def get_runs( include_in_schema=False, ) async def get_run( - run_id: str = Path(..., description="The id of the task run or the workflow run."), + run_id: str = Path( + ..., description="The id of the task run or the workflow run.", examples=["tsk_123", "tsk_v2_123", "wr_123"] + ), current_org: Organization = Depends(org_auth_service.get_current_org), ) -> RunResponse: run_response = await run_service.get_run_response(run_id, organization_id=current_org.organization_id) @@ -623,7 +637,10 @@ async def run_workflow_legacy( version: int | None = None, current_org: Organization = Depends(org_auth_service.get_current_org), template: bool = Query(False), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, x_max_steps_override: Annotated[int | None, Header()] = None, x_user_agent: Annotated[str | None, Header()] = None, ) -> RunWorkflowResponse: @@ -916,8 +933,10 @@ async def create_workflow( include_in_schema=False, ) async def update_workflow( - workflow_id: str, request: Request, + workflow_id: str = Path( + ..., description="The ID of the workflow to update. Workflow ID starts with `wpid_`.", examples=["wpid_123"] + ), current_org: Organization = Depends(org_auth_service.get_current_org), ) -> Workflow: analytics.capture("skyvern-oss-agent-workflow-update") @@ -968,7 +987,9 @@ async def update_workflow( ) @base_router.post("/workflows/{workflow_id}/delete/", include_in_schema=False) async def delete_workflow( - workflow_id: str, + workflow_id: str = Path( + ..., description="The ID of the workflow to delete. Workflow ID starts with `wpid_`.", examples=["wpid_123"] + ), current_org: Organization = Depends(org_auth_service.get_current_org), ) -> None: analytics.capture("skyvern-oss-agent-workflow-delete") @@ -1431,7 +1452,10 @@ async def run_task( background_tasks: BackgroundTasks, run_request: TaskRunRequest, current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, x_user_agent: Annotated[str | None, Header()] = None, ) -> TaskRunResponse: analytics.capture("skyvern-oss-run-task", data={"url": run_request.url}) @@ -1469,6 +1493,7 @@ async def run_task( browser_session_id=run_request.browser_session_id, totp_verification_url=run_request.totp_url, totp_identifier=run_request.totp_identifier, + include_action_history_in_verification=run_request.include_action_history_in_verification, ) task_v1_response = await task_v1_service.run_task( task=task_v1_request, @@ -1590,7 +1615,10 @@ async def run_workflow( workflow_run_request: WorkflowRunRequest, current_org: Organization = Depends(org_auth_service.get_current_org), template: bool = Query(False), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, x_max_steps_override: Annotated[int | None, Header()] = None, x_user_agent: Annotated[str | None, Header()] = None, ) -> WorkflowRunResponse: @@ -1651,7 +1679,10 @@ async def run_workflow( async def cancel_run( run_id: str = Path(..., description="The id of the task run or the workflow run to cancel."), current_org: Organization = Depends(org_auth_service.get_current_org), - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, ) -> None: analytics.capture("skyvern-oss-agent-cancel-run") diff --git a/skyvern/forge/sdk/services/org_auth_service.py b/skyvern/forge/sdk/services/org_auth_service.py index 7a5ecea0..b5304549 100644 --- a/skyvern/forge/sdk/services/org_auth_service.py +++ b/skyvern/forge/sdk/services/org_auth_service.py @@ -24,7 +24,10 @@ ALGORITHM = "HS256" async def get_current_org( - x_api_key: Annotated[str | None, Header()] = None, + x_api_key: Annotated[ + str | None, + Header(None, description='Skyvern API key for your organization. You can find it in Skyvern "Settings" page.'), + ] = None, authorization: Annotated[str | None, Header()] = None, ) -> Organization: if not x_api_key and not authorization: diff --git a/skyvern/schemas/runs.py b/skyvern/schemas/runs.py index 7c2e54ee..3475eb96 100644 --- a/skyvern/schemas/runs.py +++ b/skyvern/schemas/runs.py @@ -193,10 +193,11 @@ class TaskRunRequest(BaseModel): default=None, description="The starting URL for the task. If not provided, Skyvern will attempt to determine an appropriate URL", ) - title: str | None = Field(default=None, description="Optional title for the task") engine: RunEngine = Field( - default=RunEngine.skyvern_v2, description="The Skyvern engine version to use for this task" + default=RunEngine.skyvern_v2, + description="The Skyvern engine version to use for this task. The default value is skyvern-2.0.", ) + title: str | None = Field(default=None, description="The title for the task") proxy_location: ProxyLocation | None = Field( default=ProxyLocation.RESIDENTIAL, description="Geographic Proxy location to route the browser traffic through" ) @@ -224,8 +225,11 @@ class TaskRunRequest(BaseModel): default=None, description="ID of an existing browser session to reuse, having it continue from the current screen state", ) - publish_workflow: bool = Field(default=False, description="Whether to publish this task as a reusable workflow. ") - include_action_history_in_verification: bool = Field( + publish_workflow: bool = Field( + default=False, + description="Whether to publish this task as a reusable workflow. Only available for skyvern-2.0.", + ) + include_action_history_in_verification: bool | None = Field( default=False, description="Whether to include action history when verifying that the task is complete" ) @@ -248,26 +252,29 @@ class TaskRunRequest(BaseModel): class WorkflowRunRequest(BaseModel): - workflow_id: str = Field(description="ID of the workflow to run") - title: str | None = Field(default=None, description="Optional title for this workflow run") + workflow_id: str = Field( + description="ID of the workflow to run. Workflow ID starts with `wpid_`.", examples=["wpid_123"] + ) + title: str | None = Field(default=None, description="The title for this workflow run") parameters: dict[str, Any] = Field(default={}, description="Parameters to pass to the workflow") proxy_location: ProxyLocation = Field( default=ProxyLocation.RESIDENTIAL, description="Location of proxy to use for this workflow run" ) webhook_url: str | None = Field( - default=None, description="URL to send workflow status updates to after a run is finished" + default=None, + description="URL to send workflow status updates to after a run is finished. Refer to https://docs.skyvern.com/running-tasks/webhooks-faq for webhook questions.", ) totp_url: str | None = Field( default=None, - description="URL for TOTP authentication setup if Skyvern should be polling endpoint for 2FA codes", + description="URL that serves TOTP/2FA/MFA codes for Skyvern to use during the workflow run. Refer to https://docs.skyvern.com/running-tasks/advanced-features#get-code-from-your-endpoint", ) totp_identifier: str | None = Field( default=None, - description="Identifier for TOTP (Time-based One-Time Password) authentication if codes are being pushed to Skyvern", + description="Identifier for the TOTP/2FA/MFA code when the code is pushed to Skyvern. Refer to https://docs.skyvern.com/running-tasks/advanced-features#time-based-one-time-password-totp", ) browser_session_id: str | None = Field( default=None, - description="ID of an existing browser session to reuse, having it continue from the current screen state", + description="ID of a Skyvern browser session to reuse, having it continue from the current screen state", ) @field_validator("webhook_url", "totp_url") @@ -279,17 +286,30 @@ class WorkflowRunRequest(BaseModel): class BaseRunResponse(BaseModel): - run_id: str = Field(description="Unique identifier for this run") - status: RunStatus = Field(description="Current status of the run") + run_id: str = Field( + description="Unique identifier for this run. Run ID starts with `tsk_` for task runs and `wr_` for workflow runs.", + examples=["tsk_123", "tsk_v2_123", "wr_123"], + ) + status: RunStatus = Field( + description="Current status of the run", + examples=["created", "queued", "running", "timed_out", "failed", "terminated", "completed", "canceled"], + ) output: dict | list | str | None = Field( - default=None, description="Output data from the run, if any. Format depends on the schema in the input" + default=None, + description="Output data from the run, if any. Format/schema depends on the data extracted by the run.", ) downloaded_files: list[FileInfo] | None = Field(default=None, description="List of files downloaded during the run") recording_url: str | None = Field(default=None, description="URL to the recording of the run") - 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") + failure_reason: str | None = Field(default=None, description="Reason for failure if the run failed or terminated") + created_at: datetime = Field(description="Timestamp when this run was created", examples=["2025-01-01T00:00:00Z"]) + modified_at: datetime = Field( + description="Timestamp when this run was last modified", examples=["2025-01-01T00:05:00Z"] + ) + app_url: str | None = Field( + default=None, + description="URL to the application UI where the run can be viewed", + examples=["https://app.skyvern.com/tasks/tsk_123", "https://app.skyvern.com/workflows/wpid_123/wr_123"], + ) class TaskRunResponse(BaseRunResponse):