diff --git a/skyvern/core/script_generations/transform_workflow_run.py b/skyvern/core/script_generations/transform_workflow_run.py index 5b24341a..830087d7 100644 --- a/skyvern/core/script_generations/transform_workflow_run.py +++ b/skyvern/core/script_generations/transform_workflow_run.py @@ -5,7 +5,7 @@ import structlog from skyvern.core.script_generations.constants import SCRIPT_TASK_BLOCKS from skyvern.forge import app -from skyvern.forge.sdk.workflow.models.block import BlockType +from skyvern.schemas.workflows import BlockType from skyvern.services import workflow_service LOG = structlog.get_logger(__name__) diff --git a/skyvern/forge/sdk/artifact/storage/test_helpers.py b/skyvern/forge/sdk/artifact/storage/test_helpers.py index a1c543b7..c0ed345f 100644 --- a/skyvern/forge/sdk/artifact/storage/test_helpers.py +++ b/skyvern/forge/sdk/artifact/storage/test_helpers.py @@ -3,7 +3,8 @@ from datetime import datetime from skyvern.forge.sdk.models import Step, StepStatus from skyvern.forge.sdk.schemas.ai_suggestions import AISuggestion from skyvern.forge.sdk.schemas.task_v2 import TaskV2, Thought -from skyvern.forge.sdk.schemas.workflow_runs import BlockType, WorkflowRunBlock +from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunBlock +from skyvern.schemas.workflows import BlockType # Constants TEST_ORGANIZATION_ID = "test-org-123" diff --git a/skyvern/forge/sdk/db/client.py b/skyvern/forge/sdk/db/client.py index e472b8ed..14f61ea1 100644 --- a/skyvern/forge/sdk/db/client.py +++ b/skyvern/forge/sdk/db/client.py @@ -85,7 +85,6 @@ from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Status, Thought, Tho from skyvern.forge.sdk.schemas.tasks import OrderBy, SortDirection, Task, TaskStatus from skyvern.forge.sdk.schemas.totp_codes import TOTPCode from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunBlock -from skyvern.forge.sdk.workflow.models.block import BlockStatus, BlockType from skyvern.forge.sdk.workflow.models.parameter import ( AWSSecretParameter, BitwardenCreditCardDataParameter, @@ -103,10 +102,10 @@ from skyvern.forge.sdk.workflow.models.workflow import ( WorkflowRunOutputParameter, WorkflowRunParameter, WorkflowRunStatus, - WorkflowStatus, ) from skyvern.schemas.runs import ProxyLocation, RunEngine, RunType from skyvern.schemas.scripts import Script, ScriptBlock, ScriptFile +from skyvern.schemas.workflows import BlockStatus, BlockType, WorkflowStatus from skyvern.webeye.actions.actions import Action from skyvern.webeye.actions.models import AgentStepOutput diff --git a/skyvern/forge/sdk/db/utils.py b/skyvern/forge/sdk/db/utils.py index 28cc0875..cfd2c818 100644 --- a/skyvern/forge/sdk/db/utils.py +++ b/skyvern/forge/sdk/db/utils.py @@ -33,7 +33,6 @@ from skyvern.forge.sdk.models import Step, StepStatus from skyvern.forge.sdk.schemas.organizations import Organization, OrganizationAuthToken from skyvern.forge.sdk.schemas.tasks import Task, TaskStatus from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunBlock -from skyvern.forge.sdk.workflow.models.block import BlockStatus, BlockType from skyvern.forge.sdk.workflow.models.parameter import ( AWSSecretParameter, BitwardenLoginCredentialParameter, @@ -53,6 +52,7 @@ from skyvern.forge.sdk.workflow.models.workflow import ( ) from skyvern.schemas.runs import ProxyLocation from skyvern.schemas.scripts import Script, ScriptBlock, ScriptFile +from skyvern.schemas.workflows import BlockStatus, BlockType from skyvern.webeye.actions.actions import ( Action, ActionType, diff --git a/skyvern/forge/sdk/routes/agent_protocol.py b/skyvern/forge/sdk/routes/agent_protocol.py index 061b3d82..2340a4d2 100644 --- a/skyvern/forge/sdk/routes/agent_protocol.py +++ b/skyvern/forge/sdk/routes/agent_protocol.py @@ -68,7 +68,6 @@ from skyvern.forge.sdk.workflow.exceptions import ( InvalidTemplateWorkflowPermanentId, WorkflowParameterMissingRequiredValue, ) -from skyvern.forge.sdk.workflow.models.block import BlockType from skyvern.forge.sdk.workflow.models.workflow import ( RunWorkflowResponse, Workflow, @@ -76,9 +75,7 @@ from skyvern.forge.sdk.workflow.models.workflow import ( WorkflowRun, WorkflowRunResponseBase, WorkflowRunStatus, - WorkflowStatus, ) -from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest from skyvern.schemas.artifacts import EntityType, entity_type_to_param from skyvern.schemas.runs import ( CUA_ENGINES, @@ -92,7 +89,7 @@ from skyvern.schemas.runs import ( WorkflowRunRequest, WorkflowRunResponse, ) -from skyvern.schemas.workflows import WorkflowRequest +from skyvern.schemas.workflows import BlockType, WorkflowCreateYAMLRequest, WorkflowRequest, WorkflowStatus from skyvern.services import block_service, run_service, task_v1_service, task_v2_service, workflow_service from skyvern.webeye.actions.actions import Action diff --git a/skyvern/forge/sdk/routes/run_blocks.py b/skyvern/forge/sdk/routes/run_blocks.py index ddc79887..e1eafe3b 100644 --- a/skyvern/forge/sdk/routes/run_blocks.py +++ b/skyvern/forge/sdk/routes/run_blocks.py @@ -16,17 +16,18 @@ from skyvern.forge.sdk.routes.routers import base_router from skyvern.forge.sdk.schemas.organizations import Organization from skyvern.forge.sdk.services import org_auth_service from skyvern.forge.sdk.workflow.models.parameter import WorkflowParameterType -from skyvern.forge.sdk.workflow.models.workflow import WorkflowRequestBody, WorkflowStatus -from skyvern.forge.sdk.workflow.models.yaml import ( +from skyvern.forge.sdk.workflow.models.workflow import WorkflowRequestBody +from skyvern.schemas.run_blocks import CredentialType, LoginRequest +from skyvern.schemas.runs import ProxyLocation, RunType, WorkflowRunRequest, WorkflowRunResponse +from skyvern.schemas.workflows import ( BitwardenLoginCredentialParameterYAML, LoginBlockYAML, OnePasswordCredentialParameterYAML, WorkflowCreateYAMLRequest, WorkflowDefinitionYAML, WorkflowParameterYAML, + WorkflowStatus, ) -from skyvern.schemas.run_blocks import CredentialType, LoginRequest -from skyvern.schemas.runs import ProxyLocation, RunType, WorkflowRunRequest, WorkflowRunResponse from skyvern.services import workflow_service LOG = structlog.get_logger() diff --git a/skyvern/forge/sdk/schemas/workflow_runs.py b/skyvern/forge/sdk/schemas/workflow_runs.py index e5097d60..b8072947 100644 --- a/skyvern/forge/sdk/schemas/workflow_runs.py +++ b/skyvern/forge/sdk/schemas/workflow_runs.py @@ -7,8 +7,8 @@ from typing import Any from pydantic import BaseModel from skyvern.forge.sdk.schemas.task_v2 import Thought -from skyvern.forge.sdk.workflow.models.block import BlockType from skyvern.schemas.runs import RunEngine +from skyvern.schemas.workflows import BlockType from skyvern.webeye.actions.actions import Action diff --git a/skyvern/forge/sdk/workflow/models/block.py b/skyvern/forge/sdk/workflow/models/block.py index e8db2804..db043c54 100644 --- a/skyvern/forge/sdk/workflow/models/block.py +++ b/skyvern/forge/sdk/workflow/models/block.py @@ -13,10 +13,8 @@ import string import textwrap import uuid from collections import defaultdict -from dataclasses import dataclass from datetime import datetime from email.message import EmailMessage -from enum import StrEnum from pathlib import Path from typing import Annotated, Any, Awaitable, Callable, Literal, Union from urllib.parse import quote, urlparse @@ -75,7 +73,6 @@ from skyvern.forge.sdk.workflow.exceptions import ( NoIterableValueFound, NoValidEmailRecipient, ) -from skyvern.forge.sdk.workflow.models.constants import FileStorageType from skyvern.forge.sdk.workflow.models.parameter import ( PARAMETER_TYPE, AWSSecretParameter, @@ -85,6 +82,7 @@ from skyvern.forge.sdk.workflow.models.parameter import ( WorkflowParameter, ) from skyvern.schemas.runs import RunEngine +from skyvern.schemas.workflows import BlockResult, BlockStatus, BlockType, FileStorageType, FileType from skyvern.utils.url_validators import prepend_scheme_and_validate_url from skyvern.webeye.browser_factory import BrowserState from skyvern.webeye.utils.page import SkyvernFrame @@ -98,38 +96,6 @@ def _generate_random_string(length: int = 8) -> str: return "".join(random.choices(string.ascii_lowercase + string.digits, k=length)) -class BlockType(StrEnum): - TASK = "task" - TaskV2 = "task_v2" - FOR_LOOP = "for_loop" - CODE = "code" - TEXT_PROMPT = "text_prompt" - DOWNLOAD_TO_S3 = "download_to_s3" - UPLOAD_TO_S3 = "upload_to_s3" - FILE_UPLOAD = "file_upload" - SEND_EMAIL = "send_email" - FILE_URL_PARSER = "file_url_parser" - VALIDATION = "validation" - ACTION = "action" - NAVIGATION = "navigation" - EXTRACTION = "extraction" - LOGIN = "login" - WAIT = "wait" - FILE_DOWNLOAD = "file_download" - GOTO_URL = "goto_url" - PDF_PARSER = "pdf_parser" - HTTP_REQUEST = "http_request" - - -class BlockStatus(StrEnum): - running = "running" - completed = "completed" - failed = "failed" - terminated = "terminated" - canceled = "canceled" - timed_out = "timed_out" - - # Mapping from TaskV2Status to the corresponding BlockStatus. Declared once at # import time so it is not recreated on each block execution. TASKV2_TO_BLOCK_STATUS: dict[TaskV2Status, BlockStatus] = { @@ -141,16 +107,6 @@ TASKV2_TO_BLOCK_STATUS: dict[TaskV2Status, BlockStatus] = { } -@dataclass(frozen=True) -class BlockResult: - success: bool - output_parameter: OutputParameter - output_parameter_value: dict[str, Any] | list | str | None = None - status: BlockStatus | None = None - failure_reason: str | None = None - workflow_run_block_id: str | None = None - - class Block(BaseModel, abc.ABC): # Must be unique within workflow definition label: str @@ -2440,12 +2396,6 @@ class SendEmailBlock(Block): ) -class FileType(StrEnum): - CSV = "csv" - EXCEL = "excel" - PDF = "pdf" - - class FileParserBlock(Block): block_type: Literal[BlockType.FILE_URL_PARSER] = BlockType.FILE_URL_PARSER diff --git a/skyvern/forge/sdk/workflow/models/constants.py b/skyvern/forge/sdk/workflow/models/constants.py deleted file mode 100644 index b35d0d02..00000000 --- a/skyvern/forge/sdk/workflow/models/constants.py +++ /dev/null @@ -1,6 +0,0 @@ -from enum import StrEnum - - -class FileStorageType(StrEnum): - S3 = "s3" - AZURE = "azure" diff --git a/skyvern/forge/sdk/workflow/models/workflow.py b/skyvern/forge/sdk/workflow/models/workflow.py index 42928e73..c41655d7 100644 --- a/skyvern/forge/sdk/workflow/models/workflow.py +++ b/skyvern/forge/sdk/workflow/models/workflow.py @@ -11,6 +11,7 @@ from skyvern.forge.sdk.workflow.exceptions import WorkflowDefinitionHasDuplicate from skyvern.forge.sdk.workflow.models.block import BlockTypeVar from skyvern.forge.sdk.workflow.models.parameter import PARAMETER_TYPE from skyvern.schemas.runs import ProxyLocation +from skyvern.schemas.workflows import WorkflowStatus from skyvern.utils.url_validators import validate_url @@ -56,12 +57,6 @@ class WorkflowDefinition(BaseModel): raise WorkflowDefinitionHasDuplicateBlockLabels(duplicate_labels) -class WorkflowStatus(StrEnum): - published = "published" - draft = "draft" - auto_generated = "auto_generated" - - class Workflow(BaseModel): workflow_id: str organization_id: str diff --git a/skyvern/forge/sdk/workflow/models/yaml.py b/skyvern/forge/sdk/workflow/models/yaml.py deleted file mode 100644 index ab8f6eaf..00000000 --- a/skyvern/forge/sdk/workflow/models/yaml.py +++ /dev/null @@ -1,451 +0,0 @@ -import abc -from typing import Annotated, Any, Literal - -from pydantic import BaseModel, Field - -from skyvern.config import settings -from skyvern.forge.sdk.workflow.models.block import BlockType, FileType -from skyvern.forge.sdk.workflow.models.constants import FileStorageType -from skyvern.forge.sdk.workflow.models.parameter import ParameterType, WorkflowParameterType -from skyvern.forge.sdk.workflow.models.workflow import WorkflowStatus -from skyvern.schemas.runs import ProxyLocation, RunEngine - - -class ParameterYAML(BaseModel, abc.ABC): - parameter_type: ParameterType - key: str - description: str | None = None - - -class AWSSecretParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.AWS_SECRET] = ParameterType.AWS_SECRET # type: ignore - aws_key: str - - -class BitwardenLoginCredentialParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.BITWARDEN_LOGIN_CREDENTIAL] = ParameterType.BITWARDEN_LOGIN_CREDENTIAL # type: ignore - - # bitwarden cli required fields - bitwarden_client_id_aws_secret_key: str - bitwarden_client_secret_aws_secret_key: str - bitwarden_master_password_aws_secret_key: str - # parameter key for the url to request the login credentials from bitwarden - url_parameter_key: str | None = None - # bitwarden collection id to filter the login credentials from, - # if not provided, no filtering will be done - bitwarden_collection_id: str | None = None - # bitwarden item id to request the login credential - bitwarden_item_id: str | None = None - - -class CredentialParameterYAML(ParameterYAML): - parameter_type: Literal[ParameterType.CREDENTIAL] = ParameterType.CREDENTIAL # type: ignore - credential_id: str - - -class BitwardenSensitiveInformationParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal["bitwarden_sensitive_information"] = ParameterType.BITWARDEN_SENSITIVE_INFORMATION # type: ignore - - # bitwarden cli required fields - bitwarden_client_id_aws_secret_key: str - bitwarden_client_secret_aws_secret_key: str - bitwarden_master_password_aws_secret_key: str - # bitwarden collection id to filter the Bitwarden Identity from - bitwarden_collection_id: str - # unique key to identify the Bitwarden Identity in the collection - # this has to be in the identity's name - bitwarden_identity_key: str - # fields to extract from the Bitwarden Identity. Custom fields are prioritized over default identity fields - bitwarden_identity_fields: list[str] - - -class BitwardenCreditCardDataParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.BITWARDEN_CREDIT_CARD_DATA] = ParameterType.BITWARDEN_CREDIT_CARD_DATA # type: ignore - # bitwarden cli required fields - bitwarden_client_id_aws_secret_key: str - bitwarden_client_secret_aws_secret_key: str - bitwarden_master_password_aws_secret_key: str - # bitwarden ids for the credit card item - bitwarden_collection_id: str - bitwarden_item_id: str - - -class OnePasswordCredentialParameterYAML(ParameterYAML): - parameter_type: Literal[ParameterType.ONEPASSWORD] = ParameterType.ONEPASSWORD # type: ignore - vault_id: str - item_id: str - - -class WorkflowParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.WORKFLOW] = ParameterType.WORKFLOW # type: ignore - workflow_parameter_type: WorkflowParameterType - default_value: str | int | float | bool | dict | list | None = None - - -class ContextParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.CONTEXT] = ParameterType.CONTEXT # type: ignore - source_parameter_key: str - - -class OutputParameterYAML(ParameterYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - parameter_type: Literal[ParameterType.OUTPUT] = ParameterType.OUTPUT # type: ignore - - -class BlockYAML(BaseModel, abc.ABC): - block_type: BlockType - label: str - continue_on_failure: bool = False - model: dict[str, Any] | None = None - - -class TaskBlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.TASK] = BlockType.TASK # type: ignore - - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - navigation_goal: str | None = None - data_extraction_goal: str | None = None - data_schema: dict[str, Any] | list | str | None = None - error_code_mapping: dict[str, str] | None = None - max_retries: int = 0 - max_steps_per_run: int | None = None - parameter_keys: list[str] | None = None - complete_on_download: bool = False - download_suffix: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - cache_actions: bool = False - complete_criterion: str | None = None - terminate_criterion: str | None = None - complete_verification: bool = True - include_action_history_in_verification: bool = False - - -class ForLoopBlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.FOR_LOOP] = BlockType.FOR_LOOP # type: ignore - - loop_blocks: list["BLOCK_YAML_SUBCLASSES"] - loop_over_parameter_key: str = "" - loop_variable_reference: str | None = None - complete_if_empty: bool = False - - -class CodeBlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.CODE] = BlockType.CODE # type: ignore - - code: str - parameter_keys: list[str] | None = None - - -DEFAULT_TEXT_PROMPT_LLM_KEY = settings.SECONDARY_LLM_KEY or settings.LLM_KEY - - -class TextPromptBlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.TEXT_PROMPT] = BlockType.TEXT_PROMPT # type: ignore - - llm_key: str = DEFAULT_TEXT_PROMPT_LLM_KEY - prompt: str - parameter_keys: list[str] | None = None - json_schema: dict[str, Any] | None = None - - -class DownloadToS3BlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.DOWNLOAD_TO_S3] = BlockType.DOWNLOAD_TO_S3 # type: ignore - - url: str - - -class UploadToS3BlockYAML(BlockYAML): - block_type: Literal[BlockType.UPLOAD_TO_S3] = BlockType.UPLOAD_TO_S3 # type: ignore - - path: str | None = None - - -class FileUploadBlockYAML(BlockYAML): - block_type: Literal[BlockType.FILE_UPLOAD] = BlockType.FILE_UPLOAD # type: ignore - - storage_type: FileStorageType = FileStorageType.S3 - s3_bucket: str | None = None - aws_access_key_id: str | None = None - aws_secret_access_key: str | None = None - region_name: str | None = None - azure_storage_account_name: str | None = None - azure_storage_account_key: str | None = None - azure_blob_container_name: str | None = None - path: str | None = None - - -class SendEmailBlockYAML(BlockYAML): - # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: - # Parameter 1 of Literal[...] cannot be of type "Any" - # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able - # to infer the type of the parameter_type attribute. - block_type: Literal[BlockType.SEND_EMAIL] = BlockType.SEND_EMAIL # type: ignore - - smtp_host_secret_parameter_key: str - smtp_port_secret_parameter_key: str - smtp_username_secret_parameter_key: str - smtp_password_secret_parameter_key: str - sender: str - recipients: list[str] - subject: str - body: str - file_attachments: list[str] | None = None - - -class FileParserBlockYAML(BlockYAML): - block_type: Literal[BlockType.FILE_URL_PARSER] = BlockType.FILE_URL_PARSER # type: ignore - - file_url: str - file_type: FileType - json_schema: dict[str, Any] | None = None - - -class PDFParserBlockYAML(BlockYAML): - block_type: Literal[BlockType.PDF_PARSER] = BlockType.PDF_PARSER # type: ignore - - file_url: str - json_schema: dict[str, Any] | None = None - - -class ValidationBlockYAML(BlockYAML): - block_type: Literal[BlockType.VALIDATION] = BlockType.VALIDATION # type: ignore - - complete_criterion: str | None = None - terminate_criterion: str | None = None - error_code_mapping: dict[str, str] | None = None - parameter_keys: list[str] | None = None - - -class ActionBlockYAML(BlockYAML): - block_type: Literal[BlockType.ACTION] = BlockType.ACTION # type: ignore - - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - navigation_goal: str | None = None - error_code_mapping: dict[str, str] | None = None - max_retries: int = 0 - parameter_keys: list[str] | None = None - complete_on_download: bool = False - download_suffix: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - cache_actions: bool = False - - -class NavigationBlockYAML(BlockYAML): - block_type: Literal[BlockType.NAVIGATION] = BlockType.NAVIGATION # type: ignore - - navigation_goal: str - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - error_code_mapping: dict[str, str] | None = None - max_retries: int = 0 - max_steps_per_run: int | None = None - parameter_keys: list[str] | None = None - complete_on_download: bool = False - download_suffix: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - cache_actions: bool = False - complete_criterion: str | None = None - terminate_criterion: str | None = None - complete_verification: bool = True - include_action_history_in_verification: bool = False - - -class ExtractionBlockYAML(BlockYAML): - block_type: Literal[BlockType.EXTRACTION] = BlockType.EXTRACTION # type: ignore - - data_extraction_goal: str - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - data_schema: dict[str, Any] | list | str | None = None - max_retries: int = 0 - max_steps_per_run: int | None = None - parameter_keys: list[str] | None = None - cache_actions: bool = False - - -class LoginBlockYAML(BlockYAML): - block_type: Literal[BlockType.LOGIN] = BlockType.LOGIN # type: ignore - - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - navigation_goal: str | None = None - error_code_mapping: dict[str, str] | None = None - max_retries: int = 0 - max_steps_per_run: int | None = None - parameter_keys: list[str] | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - cache_actions: bool = False - complete_criterion: str | None = None - terminate_criterion: str | None = None - complete_verification: bool = True - - -class WaitBlockYAML(BlockYAML): - block_type: Literal[BlockType.WAIT] = BlockType.WAIT # type: ignore - wait_sec: int = 0 - - -class FileDownloadBlockYAML(BlockYAML): - block_type: Literal[BlockType.FILE_DOWNLOAD] = BlockType.FILE_DOWNLOAD # type: ignore - - navigation_goal: str - url: str | None = None - title: str = "" - engine: RunEngine = RunEngine.skyvern_v1 - error_code_mapping: dict[str, str] | None = None - max_retries: int = 0 - max_steps_per_run: int | None = None - parameter_keys: list[str] | None = None - download_suffix: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - cache_actions: bool = False - - -class UrlBlockYAML(BlockYAML): - block_type: Literal[BlockType.GOTO_URL] = BlockType.GOTO_URL # type: ignore - url: str - - -class TaskV2BlockYAML(BlockYAML): - block_type: Literal[BlockType.TaskV2] = BlockType.TaskV2 # type: ignore - prompt: str - url: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - max_iterations: int = settings.MAX_ITERATIONS_PER_TASK_V2 - max_steps: int = settings.MAX_STEPS_PER_TASK_V2 - - -class HttpRequestBlockYAML(BlockYAML): - block_type: Literal[BlockType.HTTP_REQUEST] = BlockType.HTTP_REQUEST # type: ignore - - # Individual HTTP parameters - method: str = "GET" - url: str | None = None - headers: dict[str, str] | None = None - body: dict[str, Any] | None = None # Changed to consistently be dict only - timeout: int = 30 - follow_redirects: bool = True - - # Parameter keys for templating - parameter_keys: list[str] | None = None - - -PARAMETER_YAML_SUBCLASSES = ( - AWSSecretParameterYAML - | BitwardenLoginCredentialParameterYAML - | BitwardenSensitiveInformationParameterYAML - | BitwardenCreditCardDataParameterYAML - | OnePasswordCredentialParameterYAML - | WorkflowParameterYAML - | ContextParameterYAML - | OutputParameterYAML - | CredentialParameterYAML -) -PARAMETER_YAML_TYPES = Annotated[PARAMETER_YAML_SUBCLASSES, Field(discriminator="parameter_type")] - -BLOCK_YAML_SUBCLASSES = ( - TaskBlockYAML - | ForLoopBlockYAML - | CodeBlockYAML - | TextPromptBlockYAML - | DownloadToS3BlockYAML - | UploadToS3BlockYAML - | FileUploadBlockYAML - | SendEmailBlockYAML - | FileParserBlockYAML - | ValidationBlockYAML - | ActionBlockYAML - | NavigationBlockYAML - | ExtractionBlockYAML - | LoginBlockYAML - | WaitBlockYAML - | FileDownloadBlockYAML - | UrlBlockYAML - | PDFParserBlockYAML - | TaskV2BlockYAML - | HttpRequestBlockYAML -) -BLOCK_YAML_TYPES = Annotated[BLOCK_YAML_SUBCLASSES, Field(discriminator="block_type")] - - -class WorkflowDefinitionYAML(BaseModel): - parameters: list[PARAMETER_YAML_TYPES] - blocks: list[BLOCK_YAML_TYPES] - - -class WorkflowCreateYAMLRequest(BaseModel): - title: str - description: str | None = None - proxy_location: ProxyLocation | None = None - webhook_callback_url: str | None = None - totp_verification_url: str | None = None - totp_identifier: str | None = None - persist_browser_session: bool = False - model: dict[str, Any] | None = None - workflow_definition: WorkflowDefinitionYAML - is_saved_task: bool = False - max_screenshot_scrolls: int | None = None - extra_http_headers: dict[str, str] | None = None - status: WorkflowStatus = WorkflowStatus.published - generate_script: bool = False - cache_key: str | None = None diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index 594fe2c4..b1291469 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -45,8 +45,6 @@ from skyvern.forge.sdk.workflow.exceptions import ( ) from skyvern.forge.sdk.workflow.models.block import ( ActionBlock, - BlockStatus, - BlockType, BlockTypeVar, CodeBlock, DownloadToS3Block, @@ -94,16 +92,18 @@ from skyvern.forge.sdk.workflow.models.workflow import ( WorkflowRunParameter, WorkflowRunResponseBase, WorkflowRunStatus, - WorkflowStatus, -) -from skyvern.forge.sdk.workflow.models.yaml import ( - BLOCK_YAML_TYPES, - ForLoopBlockYAML, - WorkflowCreateYAMLRequest, - WorkflowDefinitionYAML, ) from skyvern.schemas.runs import ProxyLocation, RunStatus, RunType, WorkflowRunRequest, WorkflowRunResponse from skyvern.schemas.scripts import FileEncoding, ScriptFileCreate +from skyvern.schemas.workflows import ( + BLOCK_YAML_TYPES, + BlockStatus, + BlockType, + ForLoopBlockYAML, + WorkflowCreateYAMLRequest, + WorkflowDefinitionYAML, + WorkflowStatus, +) from skyvern.services import script_service from skyvern.webeye.browser_factory import BrowserState diff --git a/skyvern/schemas/workflows.py b/skyvern/schemas/workflows.py index 22c08e50..b63f4ce1 100644 --- a/skyvern/schemas/workflows.py +++ b/skyvern/schemas/workflows.py @@ -1,6 +1,512 @@ +import abc +from dataclasses import dataclass +from enum import StrEnum +from typing import Annotated, Any, Literal + from pydantic import BaseModel, Field -from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest +from skyvern.config import settings +from skyvern.forge.sdk.workflow.models.parameter import OutputParameter, ParameterType, WorkflowParameterType +from skyvern.schemas.runs import ProxyLocation, RunEngine + + +class WorkflowStatus(StrEnum): + published = "published" + draft = "draft" + auto_generated = "auto_generated" + + +class BlockType(StrEnum): + TASK = "task" + TaskV2 = "task_v2" + FOR_LOOP = "for_loop" + CODE = "code" + TEXT_PROMPT = "text_prompt" + DOWNLOAD_TO_S3 = "download_to_s3" + UPLOAD_TO_S3 = "upload_to_s3" + FILE_UPLOAD = "file_upload" + SEND_EMAIL = "send_email" + FILE_URL_PARSER = "file_url_parser" + VALIDATION = "validation" + ACTION = "action" + NAVIGATION = "navigation" + EXTRACTION = "extraction" + LOGIN = "login" + WAIT = "wait" + FILE_DOWNLOAD = "file_download" + GOTO_URL = "goto_url" + PDF_PARSER = "pdf_parser" + HTTP_REQUEST = "http_request" + + +class BlockStatus(StrEnum): + running = "running" + completed = "completed" + failed = "failed" + terminated = "terminated" + canceled = "canceled" + timed_out = "timed_out" + + +@dataclass(frozen=True) +class BlockResult: + success: bool + output_parameter: OutputParameter + output_parameter_value: dict[str, Any] | list | str | None = None + status: BlockStatus | None = None + failure_reason: str | None = None + workflow_run_block_id: str | None = None + + +class FileType(StrEnum): + CSV = "csv" + EXCEL = "excel" + PDF = "pdf" + + +class FileStorageType(StrEnum): + S3 = "s3" + AZURE = "azure" + + +class ParameterYAML(BaseModel, abc.ABC): + parameter_type: ParameterType + key: str + description: str | None = None + + +class AWSSecretParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.AWS_SECRET] = ParameterType.AWS_SECRET # type: ignore + aws_key: str + + +class BitwardenLoginCredentialParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.BITWARDEN_LOGIN_CREDENTIAL] = ParameterType.BITWARDEN_LOGIN_CREDENTIAL # type: ignore + + # bitwarden cli required fields + bitwarden_client_id_aws_secret_key: str + bitwarden_client_secret_aws_secret_key: str + bitwarden_master_password_aws_secret_key: str + # parameter key for the url to request the login credentials from bitwarden + url_parameter_key: str | None = None + # bitwarden collection id to filter the login credentials from, + # if not provided, no filtering will be done + bitwarden_collection_id: str | None = None + # bitwarden item id to request the login credential + bitwarden_item_id: str | None = None + + +class CredentialParameterYAML(ParameterYAML): + parameter_type: Literal[ParameterType.CREDENTIAL] = ParameterType.CREDENTIAL # type: ignore + credential_id: str + + +class BitwardenSensitiveInformationParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal["bitwarden_sensitive_information"] = ParameterType.BITWARDEN_SENSITIVE_INFORMATION # type: ignore + + # bitwarden cli required fields + bitwarden_client_id_aws_secret_key: str + bitwarden_client_secret_aws_secret_key: str + bitwarden_master_password_aws_secret_key: str + # bitwarden collection id to filter the Bitwarden Identity from + bitwarden_collection_id: str + # unique key to identify the Bitwarden Identity in the collection + # this has to be in the identity's name + bitwarden_identity_key: str + # fields to extract from the Bitwarden Identity. Custom fields are prioritized over default identity fields + bitwarden_identity_fields: list[str] + + +class BitwardenCreditCardDataParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.BITWARDEN_CREDIT_CARD_DATA] = ParameterType.BITWARDEN_CREDIT_CARD_DATA # type: ignore + # bitwarden cli required fields + bitwarden_client_id_aws_secret_key: str + bitwarden_client_secret_aws_secret_key: str + bitwarden_master_password_aws_secret_key: str + # bitwarden ids for the credit card item + bitwarden_collection_id: str + bitwarden_item_id: str + + +class OnePasswordCredentialParameterYAML(ParameterYAML): + parameter_type: Literal[ParameterType.ONEPASSWORD] = ParameterType.ONEPASSWORD # type: ignore + vault_id: str + item_id: str + + +class WorkflowParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.WORKFLOW] = ParameterType.WORKFLOW # type: ignore + workflow_parameter_type: WorkflowParameterType + default_value: str | int | float | bool | dict | list | None = None + + +class ContextParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.CONTEXT] = ParameterType.CONTEXT # type: ignore + source_parameter_key: str + + +class OutputParameterYAML(ParameterYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the ParameterType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + parameter_type: Literal[ParameterType.OUTPUT] = ParameterType.OUTPUT # type: ignore + + +class BlockYAML(BaseModel, abc.ABC): + block_type: BlockType + label: str + continue_on_failure: bool = False + model: dict[str, Any] | None = None + + +class TaskBlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.TASK] = BlockType.TASK # type: ignore + + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + navigation_goal: str | None = None + data_extraction_goal: str | None = None + data_schema: dict[str, Any] | list | str | None = None + error_code_mapping: dict[str, str] | None = None + max_retries: int = 0 + max_steps_per_run: int | None = None + parameter_keys: list[str] | None = None + complete_on_download: bool = False + download_suffix: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + cache_actions: bool = False + complete_criterion: str | None = None + terminate_criterion: str | None = None + complete_verification: bool = True + include_action_history_in_verification: bool = False + + +class ForLoopBlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.FOR_LOOP] = BlockType.FOR_LOOP # type: ignore + + loop_blocks: list["BLOCK_YAML_SUBCLASSES"] + loop_over_parameter_key: str = "" + loop_variable_reference: str | None = None + complete_if_empty: bool = False + + +class CodeBlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.CODE] = BlockType.CODE # type: ignore + + code: str + parameter_keys: list[str] | None = None + + +DEFAULT_TEXT_PROMPT_LLM_KEY = settings.SECONDARY_LLM_KEY or settings.LLM_KEY + + +class TextPromptBlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.TEXT_PROMPT] = BlockType.TEXT_PROMPT # type: ignore + + llm_key: str = DEFAULT_TEXT_PROMPT_LLM_KEY + prompt: str + parameter_keys: list[str] | None = None + json_schema: dict[str, Any] | None = None + + +class DownloadToS3BlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.DOWNLOAD_TO_S3] = BlockType.DOWNLOAD_TO_S3 # type: ignore + + url: str + + +class UploadToS3BlockYAML(BlockYAML): + block_type: Literal[BlockType.UPLOAD_TO_S3] = BlockType.UPLOAD_TO_S3 # type: ignore + + path: str | None = None + + +class FileUploadBlockYAML(BlockYAML): + block_type: Literal[BlockType.FILE_UPLOAD] = BlockType.FILE_UPLOAD # type: ignore + + storage_type: FileStorageType = FileStorageType.S3 + s3_bucket: str | None = None + aws_access_key_id: str | None = None + aws_secret_access_key: str | None = None + region_name: str | None = None + azure_storage_account_name: str | None = None + azure_storage_account_key: str | None = None + azure_blob_container_name: str | None = None + path: str | None = None + + +class SendEmailBlockYAML(BlockYAML): + # There is a mypy bug with Literal. Without the type: ignore, mypy will raise an error: + # Parameter 1 of Literal[...] cannot be of type "Any" + # This pattern already works in block.py but since the BlockType is not defined in this file, mypy is not able + # to infer the type of the parameter_type attribute. + block_type: Literal[BlockType.SEND_EMAIL] = BlockType.SEND_EMAIL # type: ignore + + smtp_host_secret_parameter_key: str + smtp_port_secret_parameter_key: str + smtp_username_secret_parameter_key: str + smtp_password_secret_parameter_key: str + sender: str + recipients: list[str] + subject: str + body: str + file_attachments: list[str] | None = None + + +class FileParserBlockYAML(BlockYAML): + block_type: Literal[BlockType.FILE_URL_PARSER] = BlockType.FILE_URL_PARSER # type: ignore + + file_url: str + file_type: FileType + json_schema: dict[str, Any] | None = None + + +class PDFParserBlockYAML(BlockYAML): + block_type: Literal[BlockType.PDF_PARSER] = BlockType.PDF_PARSER # type: ignore + + file_url: str + json_schema: dict[str, Any] | None = None + + +class ValidationBlockYAML(BlockYAML): + block_type: Literal[BlockType.VALIDATION] = BlockType.VALIDATION # type: ignore + + complete_criterion: str | None = None + terminate_criterion: str | None = None + error_code_mapping: dict[str, str] | None = None + parameter_keys: list[str] | None = None + + +class ActionBlockYAML(BlockYAML): + block_type: Literal[BlockType.ACTION] = BlockType.ACTION # type: ignore + + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + navigation_goal: str | None = None + error_code_mapping: dict[str, str] | None = None + max_retries: int = 0 + parameter_keys: list[str] | None = None + complete_on_download: bool = False + download_suffix: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + cache_actions: bool = False + + +class NavigationBlockYAML(BlockYAML): + block_type: Literal[BlockType.NAVIGATION] = BlockType.NAVIGATION # type: ignore + + navigation_goal: str + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + error_code_mapping: dict[str, str] | None = None + max_retries: int = 0 + max_steps_per_run: int | None = None + parameter_keys: list[str] | None = None + complete_on_download: bool = False + download_suffix: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + cache_actions: bool = False + complete_criterion: str | None = None + terminate_criterion: str | None = None + complete_verification: bool = True + include_action_history_in_verification: bool = False + + +class ExtractionBlockYAML(BlockYAML): + block_type: Literal[BlockType.EXTRACTION] = BlockType.EXTRACTION # type: ignore + + data_extraction_goal: str + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + data_schema: dict[str, Any] | list | str | None = None + max_retries: int = 0 + max_steps_per_run: int | None = None + parameter_keys: list[str] | None = None + cache_actions: bool = False + + +class LoginBlockYAML(BlockYAML): + block_type: Literal[BlockType.LOGIN] = BlockType.LOGIN # type: ignore + + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + navigation_goal: str | None = None + error_code_mapping: dict[str, str] | None = None + max_retries: int = 0 + max_steps_per_run: int | None = None + parameter_keys: list[str] | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + cache_actions: bool = False + complete_criterion: str | None = None + terminate_criterion: str | None = None + complete_verification: bool = True + + +class WaitBlockYAML(BlockYAML): + block_type: Literal[BlockType.WAIT] = BlockType.WAIT # type: ignore + wait_sec: int = 0 + + +class FileDownloadBlockYAML(BlockYAML): + block_type: Literal[BlockType.FILE_DOWNLOAD] = BlockType.FILE_DOWNLOAD # type: ignore + + navigation_goal: str + url: str | None = None + title: str = "" + engine: RunEngine = RunEngine.skyvern_v1 + error_code_mapping: dict[str, str] | None = None + max_retries: int = 0 + max_steps_per_run: int | None = None + parameter_keys: list[str] | None = None + download_suffix: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + cache_actions: bool = False + + +class UrlBlockYAML(BlockYAML): + block_type: Literal[BlockType.GOTO_URL] = BlockType.GOTO_URL # type: ignore + url: str + + +class TaskV2BlockYAML(BlockYAML): + block_type: Literal[BlockType.TaskV2] = BlockType.TaskV2 # type: ignore + prompt: str + url: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + max_iterations: int = settings.MAX_ITERATIONS_PER_TASK_V2 + max_steps: int = settings.MAX_STEPS_PER_TASK_V2 + + +class HttpRequestBlockYAML(BlockYAML): + block_type: Literal[BlockType.HTTP_REQUEST] = BlockType.HTTP_REQUEST # type: ignore + + # Individual HTTP parameters + method: str = "GET" + url: str | None = None + headers: dict[str, str] | None = None + body: dict[str, Any] | None = None # Changed to consistently be dict only + timeout: int = 30 + follow_redirects: bool = True + + # Parameter keys for templating + parameter_keys: list[str] | None = None + + +PARAMETER_YAML_SUBCLASSES = ( + AWSSecretParameterYAML + | BitwardenLoginCredentialParameterYAML + | BitwardenSensitiveInformationParameterYAML + | BitwardenCreditCardDataParameterYAML + | OnePasswordCredentialParameterYAML + | WorkflowParameterYAML + | ContextParameterYAML + | OutputParameterYAML + | CredentialParameterYAML +) +PARAMETER_YAML_TYPES = Annotated[PARAMETER_YAML_SUBCLASSES, Field(discriminator="parameter_type")] + +BLOCK_YAML_SUBCLASSES = ( + TaskBlockYAML + | ForLoopBlockYAML + | CodeBlockYAML + | TextPromptBlockYAML + | DownloadToS3BlockYAML + | UploadToS3BlockYAML + | FileUploadBlockYAML + | SendEmailBlockYAML + | FileParserBlockYAML + | ValidationBlockYAML + | ActionBlockYAML + | NavigationBlockYAML + | ExtractionBlockYAML + | LoginBlockYAML + | WaitBlockYAML + | FileDownloadBlockYAML + | UrlBlockYAML + | PDFParserBlockYAML + | TaskV2BlockYAML + | HttpRequestBlockYAML +) +BLOCK_YAML_TYPES = Annotated[BLOCK_YAML_SUBCLASSES, Field(discriminator="block_type")] + + +class WorkflowDefinitionYAML(BaseModel): + parameters: list[PARAMETER_YAML_TYPES] + blocks: list[BLOCK_YAML_TYPES] + + +class WorkflowCreateYAMLRequest(BaseModel): + title: str + description: str | None = None + proxy_location: ProxyLocation | None = None + webhook_callback_url: str | None = None + totp_verification_url: str | None = None + totp_identifier: str | None = None + persist_browser_session: bool = False + model: dict[str, Any] | None = None + workflow_definition: WorkflowDefinitionYAML + is_saved_task: bool = False + max_screenshot_scrolls: int | None = None + extra_http_headers: dict[str, str] | None = None + status: WorkflowStatus = WorkflowStatus.published + generate_script: bool = False + cache_key: str | None = None class WorkflowRequest(BaseModel): diff --git a/skyvern/services/task_v2_service.py b/skyvern/services/task_v2_service.py index 6ca5c7d0..b4257b67 100644 --- a/skyvern/services/task_v2_service.py +++ b/skyvern/services/task_v2_service.py @@ -32,8 +32,6 @@ from skyvern.forge.sdk.schemas.task_v2 import TaskV2, TaskV2Metadata, TaskV2Stat from skyvern.forge.sdk.schemas.workflow_runs import WorkflowRunTimeline, WorkflowRunTimelineType from skyvern.forge.sdk.trace import TraceManager from skyvern.forge.sdk.workflow.models.block import ( - BlockResult, - BlockStatus, BlockTypeVar, ExtractionBlock, ForLoopBlock, @@ -42,16 +40,13 @@ from skyvern.forge.sdk.workflow.models.block import ( UrlBlock, ) from skyvern.forge.sdk.workflow.models.parameter import PARAMETER_TYPE, ContextParameter -from skyvern.forge.sdk.workflow.models.workflow import ( - Workflow, - WorkflowRequestBody, - WorkflowRun, - WorkflowRunStatus, - WorkflowStatus, -) -from skyvern.forge.sdk.workflow.models.yaml import ( +from skyvern.forge.sdk.workflow.models.workflow import Workflow, WorkflowRequestBody, WorkflowRun, WorkflowRunStatus +from skyvern.schemas.runs import ProxyLocation, RunEngine, RunType, TaskRunRequest, TaskRunResponse +from skyvern.schemas.workflows import ( BLOCK_YAML_TYPES, PARAMETER_YAML_TYPES, + BlockResult, + BlockStatus, ContextParameterYAML, ExtractionBlockYAML, ForLoopBlockYAML, @@ -60,8 +55,8 @@ from skyvern.forge.sdk.workflow.models.yaml import ( UrlBlockYAML, WorkflowCreateYAMLRequest, WorkflowDefinitionYAML, + WorkflowStatus, ) -from skyvern.schemas.runs import ProxyLocation, RunEngine, RunType, TaskRunRequest, TaskRunResponse from skyvern.utils.prompt_engine import load_prompt_with_elements from skyvern.webeye.browser_factory import BrowserState from skyvern.webeye.scraper.scraper import ScrapedPage, scrape_website