Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add navigation, login, extraction workflow blocks #1238

Merged
merged 1 commit into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions skyvern/forge/sdk/workflow/models/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
LawyZheng marked this conversation as resolved.
Show resolved Hide resolved
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,
Expand All @@ -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")]
48 changes: 48 additions & 0 deletions skyvern/forge/sdk/workflow/models/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -255,6 +300,9 @@ class ActionBlockYAML(BlockYAML):
| FileParserBlockYAML
| ValidationBlockYAML
| ActionBlockYAML
| NavigationBlockYAML
| ExtractionBlockYAML
| LoginBlockYAML
)
BLOCK_YAML_TYPES = Annotated[BLOCK_YAML_SUBCLASSES, Field(discriminator="block_type")]

Expand Down
69 changes: 69 additions & 0 deletions skyvern/forge/sdk/workflow/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@
BlockTypeVar,
CodeBlock,
DownloadToS3Block,
ExtractionBlock,
FileParserBlock,
ForLoopBlock,
LoginBlock,
NavigationBlock,
SendEmailBlock,
TaskBlock,
TextPromptBlock,
Expand Down Expand Up @@ -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}")
Loading