diff --git a/skyvern/forge/sdk/workflow/models/block.py b/skyvern/forge/sdk/workflow/models/block.py index fd3a44c0e..6027aec95 100644 --- a/skyvern/forge/sdk/workflow/models/block.py +++ b/skyvern/forge/sdk/workflow/models/block.py @@ -74,6 +74,9 @@ class BlockType(StrEnum): FILE_URL_PARSER = "file_url_parser" VALIDATION = "validation" ACTION = "action" + NAVIGATION = "navigation" + EXTRACTION = "extraction" + LOGIN = "login" class BlockStatus(StrEnum): @@ -1336,6 +1339,18 @@ async def execute(self, workflow_run_id: str, **kwargs: dict) -> BlockResult: return await super().execute(workflow_run_id=workflow_run_id, kwargs=kwargs) +class NavigationBlock(BaseTaskBlock): + block_type: Literal[BlockType.NAVIGATION] = BlockType.NAVIGATION + + +class ExtractionBlock(BaseTaskBlock): + block_type: Literal[BlockType.EXTRACTION] = BlockType.EXTRACTION + + +class LoginBlock(BaseTaskBlock): + block_type: Literal[BlockType.LOGIN] = BlockType.LOGIN + + BlockSubclasses = Union[ ForLoopBlock, TaskBlock, @@ -1347,5 +1362,8 @@ async def execute(self, workflow_run_id: str, **kwargs: dict) -> BlockResult: FileParserBlock, ValidationBlock, ActionBlock, + NavigationBlock, + ExtractionBlock, + LoginBlock, ] BlockTypeVar = Annotated[BlockSubclasses, Field(discriminator="block_type")] diff --git a/skyvern/forge/sdk/workflow/models/yaml.py b/skyvern/forge/sdk/workflow/models/yaml.py index d22c93b27..dc77b0a98 100644 --- a/skyvern/forge/sdk/workflow/models/yaml.py +++ b/skyvern/forge/sdk/workflow/models/yaml.py @@ -233,6 +233,51 @@ class ActionBlockYAML(BlockYAML): cache_actions: bool = False +class NavigationBlockYAML(BlockYAML): + block_type: Literal[BlockType.NAVIGATION] = BlockType.NAVIGATION # type: ignore + + url: str | None = None + title: str = "" + 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 + 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 ExtractionBlockYAML(BlockYAML): + block_type: Literal[BlockType.EXTRACTION] = BlockType.EXTRACTION # type: ignore + + url: str | None = None + title: str = "" + data_extraction_goal: str | None = None + data_schema: dict[str, Any] | list | 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 = "" + 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 + + PARAMETER_YAML_SUBCLASSES = ( AWSSecretParameterYAML | BitwardenLoginCredentialParameterYAML @@ -255,6 +300,9 @@ class ActionBlockYAML(BlockYAML): | FileParserBlockYAML | ValidationBlockYAML | ActionBlockYAML + | NavigationBlockYAML + | ExtractionBlockYAML + | LoginBlockYAML ) BLOCK_YAML_TYPES = Annotated[BLOCK_YAML_SUBCLASSES, Field(discriminator="block_type")] diff --git a/skyvern/forge/sdk/workflow/service.py b/skyvern/forge/sdk/workflow/service.py index c6cc90ee3..cfb32b027 100644 --- a/skyvern/forge/sdk/workflow/service.py +++ b/skyvern/forge/sdk/workflow/service.py @@ -35,8 +35,11 @@ BlockTypeVar, CodeBlock, DownloadToS3Block, + ExtractionBlock, FileParserBlock, ForLoopBlock, + LoginBlock, + NavigationBlock, SendEmailBlock, TaskBlock, TextPromptBlock, @@ -1387,4 +1390,70 @@ async def block_yaml_to_block( max_steps_per_run=1, ) + elif block_yaml.block_type == BlockType.NAVIGATION: + navigation_block_parameters = ( + [parameters[parameter_key] for parameter_key in block_yaml.parameter_keys] + if block_yaml.parameter_keys + else [] + ) + return NavigationBlock( + label=block_yaml.label, + url=block_yaml.url, + title=block_yaml.title, + parameters=navigation_block_parameters, + output_parameter=output_parameter, + navigation_goal=block_yaml.navigation_goal, + error_code_mapping=block_yaml.error_code_mapping, + max_steps_per_run=block_yaml.max_steps_per_run, + max_retries=block_yaml.max_retries, + complete_on_download=block_yaml.complete_on_download, + download_suffix=block_yaml.download_suffix, + continue_on_failure=block_yaml.continue_on_failure, + totp_verification_url=block_yaml.totp_verification_url, + totp_identifier=block_yaml.totp_identifier, + cache_actions=block_yaml.cache_actions, + ) + + elif block_yaml.block_type == BlockType.EXTRACTION: + extraction_block_parameters = ( + [parameters[parameter_key] for parameter_key in block_yaml.parameter_keys] + if block_yaml.parameter_keys + else [] + ) + return ExtractionBlock( + label=block_yaml.label, + url=block_yaml.url, + title=block_yaml.title, + parameters=extraction_block_parameters, + output_parameter=output_parameter, + data_extraction_goal=block_yaml.data_extraction_goal, + data_schema=block_yaml.data_schema, + max_steps_per_run=block_yaml.max_steps_per_run, + max_retries=block_yaml.max_retries, + continue_on_failure=block_yaml.continue_on_failure, + cache_actions=block_yaml.cache_actions, + ) + + elif block_yaml.block_type == BlockType.LOGIN: + login_block_parameters = ( + [parameters[parameter_key] for parameter_key in block_yaml.parameter_keys] + if block_yaml.parameter_keys + else [] + ) + return LoginBlock( + label=block_yaml.label, + url=block_yaml.url, + title=block_yaml.title, + parameters=login_block_parameters, + output_parameter=output_parameter, + navigation_goal=block_yaml.navigation_goal, + error_code_mapping=block_yaml.error_code_mapping, + max_steps_per_run=block_yaml.max_steps_per_run, + max_retries=block_yaml.max_retries, + continue_on_failure=block_yaml.continue_on_failure, + totp_verification_url=block_yaml.totp_verification_url, + totp_identifier=block_yaml.totp_identifier, + cache_actions=block_yaml.cache_actions, + ) + raise ValueError(f"Invalid block type {block_yaml.block_type}")