Skyvern/skyvern/forge/sdk/db/utils.py

423 lines
18 KiB
Python

import json
import typing
import pydantic.json
import structlog
from skyvern.forge.sdk.artifact.models import Artifact, ArtifactType
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
from skyvern.forge.sdk.db.models import (
ArtifactModel,
AWSSecretParameterModel,
BitwardenLoginCredentialParameterModel,
BitwardenSensitiveInformationParameterModel,
OrganizationAuthTokenModel,
OrganizationModel,
OutputParameterModel,
StepModel,
TaskModel,
WorkflowModel,
WorkflowParameterModel,
WorkflowRunBlockModel,
WorkflowRunModel,
WorkflowRunOutputParameterModel,
WorkflowRunParameterModel,
)
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,
BitwardenSensitiveInformationParameter,
OutputParameter,
WorkflowParameter,
WorkflowParameterType,
)
from skyvern.forge.sdk.workflow.models.workflow import (
Workflow,
WorkflowDefinition,
WorkflowRun,
WorkflowRunOutputParameter,
WorkflowRunParameter,
WorkflowRunStatus,
WorkflowStatus,
)
from skyvern.schemas.runs import ProxyLocation
LOG = structlog.get_logger()
@typing.no_type_check
def _custom_json_serializer(*args, **kwargs) -> str:
"""
Encodes json in the same way that pydantic does.
"""
return json.dumps(*args, default=pydantic.json.pydantic_encoder, **kwargs)
def convert_to_task(task_obj: TaskModel, debug_enabled: bool = False) -> Task:
if debug_enabled:
LOG.debug("Converting TaskModel to Task", task_id=task_obj.task_id)
task = Task(
task_id=task_obj.task_id,
status=TaskStatus(task_obj.status),
created_at=task_obj.created_at,
modified_at=task_obj.modified_at,
task_type=task_obj.task_type,
title=task_obj.title,
url=task_obj.url,
complete_criterion=task_obj.complete_criterion,
terminate_criterion=task_obj.terminate_criterion,
webhook_callback_url=task_obj.webhook_callback_url,
totp_verification_url=task_obj.totp_verification_url,
totp_identifier=task_obj.totp_identifier,
navigation_goal=task_obj.navigation_goal,
data_extraction_goal=task_obj.data_extraction_goal,
navigation_payload=task_obj.navigation_payload,
extracted_information=task_obj.extracted_information,
failure_reason=task_obj.failure_reason,
organization_id=task_obj.organization_id,
proxy_location=(ProxyLocation(task_obj.proxy_location) if task_obj.proxy_location else None),
extracted_information_schema=task_obj.extracted_information_schema,
workflow_run_id=task_obj.workflow_run_id,
order=task_obj.order,
retry=task_obj.retry,
max_steps_per_run=task_obj.max_steps_per_run,
error_code_mapping=task_obj.error_code_mapping,
errors=task_obj.errors,
application=task_obj.application,
)
return task
def convert_to_step(step_model: StepModel, debug_enabled: bool = False) -> Step:
if debug_enabled:
LOG.debug("Converting StepModel to Step", step_id=step_model.step_id)
return Step(
task_id=step_model.task_id,
step_id=step_model.step_id,
created_at=step_model.created_at,
modified_at=step_model.modified_at,
status=StepStatus(step_model.status),
output=step_model.output,
order=step_model.order,
is_last=step_model.is_last,
retry_index=step_model.retry_index,
organization_id=step_model.organization_id,
input_token_count=step_model.input_token_count,
output_token_count=step_model.output_token_count,
reasoning_token_count=step_model.reasoning_token_count,
cached_token_count=step_model.cached_token_count,
step_cost=step_model.step_cost,
)
def convert_to_organization(org_model: OrganizationModel) -> Organization:
return Organization(
organization_id=org_model.organization_id,
organization_name=org_model.organization_name,
webhook_callback_url=org_model.webhook_callback_url,
max_steps_per_run=org_model.max_steps_per_run,
max_retries_per_step=org_model.max_retries_per_step,
domain=org_model.domain,
bw_organization_id=org_model.bw_organization_id,
bw_collection_ids=org_model.bw_collection_ids,
created_at=org_model.created_at,
modified_at=org_model.modified_at,
)
def convert_to_organization_auth_token(
org_auth_token: OrganizationAuthTokenModel,
) -> OrganizationAuthToken:
return OrganizationAuthToken(
id=org_auth_token.id,
organization_id=org_auth_token.organization_id,
token_type=OrganizationAuthTokenType(org_auth_token.token_type),
token=org_auth_token.token,
valid=org_auth_token.valid,
created_at=org_auth_token.created_at,
modified_at=org_auth_token.modified_at,
)
def convert_to_artifact(artifact_model: ArtifactModel, debug_enabled: bool = False) -> Artifact:
if debug_enabled:
LOG.debug(
"Converting ArtifactModel to Artifact",
artifact_id=artifact_model.artifact_id,
)
return Artifact(
artifact_id=artifact_model.artifact_id,
artifact_type=ArtifactType[artifact_model.artifact_type.upper()],
uri=artifact_model.uri,
task_id=artifact_model.task_id,
step_id=artifact_model.step_id,
workflow_run_id=artifact_model.workflow_run_id,
workflow_run_block_id=artifact_model.workflow_run_block_id,
observer_cruise_id=artifact_model.observer_cruise_id,
observer_thought_id=artifact_model.observer_thought_id,
created_at=artifact_model.created_at,
modified_at=artifact_model.modified_at,
organization_id=artifact_model.organization_id,
)
def convert_to_workflow(workflow_model: WorkflowModel, debug_enabled: bool = False) -> Workflow:
if debug_enabled:
LOG.debug(
"Converting WorkflowModel to Workflow",
workflow_id=workflow_model.workflow_id,
)
return Workflow(
workflow_id=workflow_model.workflow_id,
organization_id=workflow_model.organization_id,
title=workflow_model.title,
workflow_permanent_id=workflow_model.workflow_permanent_id,
webhook_callback_url=workflow_model.webhook_callback_url,
totp_verification_url=workflow_model.totp_verification_url,
totp_identifier=workflow_model.totp_identifier,
persist_browser_session=workflow_model.persist_browser_session,
proxy_location=(ProxyLocation(workflow_model.proxy_location) if workflow_model.proxy_location else None),
version=workflow_model.version,
is_saved_task=workflow_model.is_saved_task,
description=workflow_model.description,
workflow_definition=WorkflowDefinition.model_validate(workflow_model.workflow_definition),
created_at=workflow_model.created_at,
modified_at=workflow_model.modified_at,
deleted_at=workflow_model.deleted_at,
status=WorkflowStatus(workflow_model.status),
)
def convert_to_workflow_run(
workflow_run_model: WorkflowRunModel, workflow_title: str | None = None, debug_enabled: bool = False
) -> WorkflowRun:
if debug_enabled:
LOG.debug(
"Converting WorkflowRunModel to WorkflowRun",
workflow_run_id=workflow_run_model.workflow_run_id,
)
return WorkflowRun(
workflow_run_id=workflow_run_model.workflow_run_id,
workflow_permanent_id=workflow_run_model.workflow_permanent_id,
parent_workflow_run_id=workflow_run_model.parent_workflow_run_id,
workflow_id=workflow_run_model.workflow_id,
organization_id=workflow_run_model.organization_id,
status=WorkflowRunStatus[workflow_run_model.status],
failure_reason=workflow_run_model.failure_reason,
proxy_location=(
ProxyLocation(workflow_run_model.proxy_location) if workflow_run_model.proxy_location else None
),
webhook_callback_url=workflow_run_model.webhook_callback_url,
totp_verification_url=workflow_run_model.totp_verification_url,
totp_identifier=workflow_run_model.totp_identifier,
created_at=workflow_run_model.created_at,
modified_at=workflow_run_model.modified_at,
workflow_title=workflow_title,
)
def convert_to_workflow_parameter(
workflow_parameter_model: WorkflowParameterModel, debug_enabled: bool = False
) -> WorkflowParameter:
if debug_enabled:
LOG.debug(
"Converting WorkflowParameterModel to WorkflowParameter",
workflow_parameter_id=workflow_parameter_model.workflow_parameter_id,
)
workflow_parameter_type = WorkflowParameterType[workflow_parameter_model.workflow_parameter_type.upper()]
return WorkflowParameter(
workflow_parameter_id=workflow_parameter_model.workflow_parameter_id,
workflow_parameter_type=workflow_parameter_type,
workflow_id=workflow_parameter_model.workflow_id,
default_value=workflow_parameter_type.convert_value(workflow_parameter_model.default_value),
key=workflow_parameter_model.key,
description=workflow_parameter_model.description,
created_at=workflow_parameter_model.created_at,
modified_at=workflow_parameter_model.modified_at,
deleted_at=workflow_parameter_model.deleted_at,
)
def convert_to_aws_secret_parameter(
aws_secret_parameter_model: AWSSecretParameterModel, debug_enabled: bool = False
) -> AWSSecretParameter:
if debug_enabled:
LOG.debug(
"Converting AWSSecretParameterModel to AWSSecretParameter",
aws_secret_parameter_id=aws_secret_parameter_model.aws_secret_parameter_id,
)
return AWSSecretParameter(
aws_secret_parameter_id=aws_secret_parameter_model.aws_secret_parameter_id,
workflow_id=aws_secret_parameter_model.workflow_id,
key=aws_secret_parameter_model.key,
description=aws_secret_parameter_model.description,
aws_key=aws_secret_parameter_model.aws_key,
created_at=aws_secret_parameter_model.created_at,
modified_at=aws_secret_parameter_model.modified_at,
deleted_at=aws_secret_parameter_model.deleted_at,
)
def convert_to_bitwarden_login_credential_parameter(
bitwarden_login_credential_parameter_model: BitwardenLoginCredentialParameterModel,
debug_enabled: bool = False,
) -> BitwardenLoginCredentialParameter:
if debug_enabled:
LOG.debug(
"Converting BitwardenLoginCredentialParameterModel to BitwardenLoginCredentialParameter",
bitwarden_login_credential_parameter_id=bitwarden_login_credential_parameter_model.bitwarden_login_credential_parameter_id,
bitwarden_collection_id=bitwarden_login_credential_parameter_model.bitwarden_collection_id,
)
return BitwardenLoginCredentialParameter(
bitwarden_login_credential_parameter_id=bitwarden_login_credential_parameter_model.bitwarden_login_credential_parameter_id,
workflow_id=bitwarden_login_credential_parameter_model.workflow_id,
key=bitwarden_login_credential_parameter_model.key,
description=bitwarden_login_credential_parameter_model.description,
bitwarden_client_id_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_id_aws_secret_key,
bitwarden_client_secret_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_secret_aws_secret_key,
bitwarden_master_password_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_master_password_aws_secret_key,
bitwarden_collection_id=bitwarden_login_credential_parameter_model.bitwarden_collection_id,
bitwarden_item_id=bitwarden_login_credential_parameter_model.bitwarden_item_id,
url_parameter_key=bitwarden_login_credential_parameter_model.url_parameter_key,
created_at=bitwarden_login_credential_parameter_model.created_at,
modified_at=bitwarden_login_credential_parameter_model.modified_at,
deleted_at=bitwarden_login_credential_parameter_model.deleted_at,
)
def convert_to_bitwarden_sensitive_information_parameter(
bitwarden_sensitive_information_parameter_model: BitwardenSensitiveInformationParameterModel,
debug_enabled: bool = False,
) -> BitwardenSensitiveInformationParameter:
if debug_enabled:
LOG.debug(
"Converting BitwardenSensitiveInformationParameterModel to BitwardenSensitiveInformationParameter",
bitwarden_sensitive_information_parameter_id=bitwarden_sensitive_information_parameter_model.bitwarden_sensitive_information_parameter_id,
)
return BitwardenSensitiveInformationParameter(
bitwarden_sensitive_information_parameter_id=bitwarden_sensitive_information_parameter_model.bitwarden_sensitive_information_parameter_id,
workflow_id=bitwarden_sensitive_information_parameter_model.workflow_id,
key=bitwarden_sensitive_information_parameter_model.key,
description=bitwarden_sensitive_information_parameter_model.description,
bitwarden_client_id_aws_secret_key=bitwarden_sensitive_information_parameter_model.bitwarden_client_id_aws_secret_key,
bitwarden_client_secret_aws_secret_key=bitwarden_sensitive_information_parameter_model.bitwarden_client_secret_aws_secret_key,
bitwarden_master_password_aws_secret_key=bitwarden_sensitive_information_parameter_model.bitwarden_master_password_aws_secret_key,
bitwarden_collection_id=bitwarden_sensitive_information_parameter_model.bitwarden_collection_id,
bitwarden_identity_key=bitwarden_sensitive_information_parameter_model.bitwarden_identity_key,
bitwarden_identity_fields=bitwarden_sensitive_information_parameter_model.bitwarden_identity_fields,
created_at=bitwarden_sensitive_information_parameter_model.created_at,
modified_at=bitwarden_sensitive_information_parameter_model.modified_at,
deleted_at=bitwarden_sensitive_information_parameter_model.deleted_at,
)
def convert_to_output_parameter(
output_parameter_model: OutputParameterModel, debug_enabled: bool = False
) -> OutputParameter:
if debug_enabled:
LOG.debug(
"Converting OutputParameterModel to OutputParameter",
output_parameter_id=output_parameter_model.output_parameter_id,
)
return OutputParameter(
output_parameter_id=output_parameter_model.output_parameter_id,
key=output_parameter_model.key,
description=output_parameter_model.description,
workflow_id=output_parameter_model.workflow_id,
created_at=output_parameter_model.created_at,
modified_at=output_parameter_model.modified_at,
deleted_at=output_parameter_model.deleted_at,
)
def convert_to_workflow_run_output_parameter(
workflow_run_output_parameter_model: WorkflowRunOutputParameterModel,
debug_enabled: bool = False,
) -> WorkflowRunOutputParameter:
if debug_enabled:
LOG.debug(
"Converting WorkflowRunOutputParameterModel to WorkflowRunOutputParameter",
workflow_run_id=workflow_run_output_parameter_model.workflow_run_id,
output_parameter_id=workflow_run_output_parameter_model.output_parameter_id,
)
return WorkflowRunOutputParameter(
workflow_run_id=workflow_run_output_parameter_model.workflow_run_id,
output_parameter_id=workflow_run_output_parameter_model.output_parameter_id,
value=workflow_run_output_parameter_model.value,
created_at=workflow_run_output_parameter_model.created_at,
)
def convert_to_workflow_run_parameter(
workflow_run_parameter_model: WorkflowRunParameterModel,
workflow_parameter: WorkflowParameter,
debug_enabled: bool = False,
) -> WorkflowRunParameter:
if debug_enabled:
LOG.debug(
"Converting WorkflowRunParameterModel to WorkflowRunParameter",
workflow_run_id=workflow_run_parameter_model.workflow_run_id,
workflow_parameter_id=workflow_run_parameter_model.workflow_parameter_id,
)
return WorkflowRunParameter(
workflow_run_id=workflow_run_parameter_model.workflow_run_id,
workflow_parameter_id=workflow_run_parameter_model.workflow_parameter_id,
value=workflow_parameter.workflow_parameter_type.convert_value(workflow_run_parameter_model.value),
created_at=workflow_run_parameter_model.created_at,
)
def convert_to_workflow_run_block(
workflow_run_block_model: WorkflowRunBlockModel,
task: Task | None = None,
) -> WorkflowRunBlock:
block = WorkflowRunBlock(
workflow_run_block_id=workflow_run_block_model.workflow_run_block_id,
workflow_run_id=workflow_run_block_model.workflow_run_id,
block_workflow_run_id=workflow_run_block_model.block_workflow_run_id,
organization_id=workflow_run_block_model.organization_id,
parent_workflow_run_block_id=workflow_run_block_model.parent_workflow_run_block_id,
description=workflow_run_block_model.description,
block_type=BlockType(workflow_run_block_model.block_type),
label=workflow_run_block_model.label,
status=BlockStatus(workflow_run_block_model.status),
output=workflow_run_block_model.output,
continue_on_failure=workflow_run_block_model.continue_on_failure,
failure_reason=workflow_run_block_model.failure_reason,
task_id=workflow_run_block_model.task_id,
loop_values=workflow_run_block_model.loop_values,
current_value=workflow_run_block_model.current_value,
current_index=workflow_run_block_model.current_index,
recipients=workflow_run_block_model.recipients,
attachments=workflow_run_block_model.attachments,
subject=workflow_run_block_model.subject,
body=workflow_run_block_model.body,
created_at=workflow_run_block_model.created_at,
modified_at=workflow_run_block_model.modified_at,
)
if task:
block.url = task.url
block.navigation_goal = task.navigation_goal
block.navigation_payload = task.navigation_payload
block.data_extraction_goal = task.data_extraction_goal
block.data_schema = task.extracted_information_schema
block.terminate_criterion = task.terminate_criterion
block.complete_criterion = task.complete_criterion
return block