new create_workflow and update_workflow endpoint that supports either json or yaml format (#2408)

This commit is contained in:
Shuchang Zheng
2025-05-20 18:43:20 -07:00
committed by GitHub
parent c1f3a282f4
commit a626d0c75f
3 changed files with 452 additions and 305 deletions

View File

@@ -26,11 +26,13 @@ from skyvern.forge.sdk.models import Step
from skyvern.forge.sdk.routes.code_samples import ( from skyvern.forge.sdk.routes.code_samples import (
CANCEL_RUN_CODE_SAMPLE, CANCEL_RUN_CODE_SAMPLE,
CREATE_WORKFLOW_CODE_SAMPLE, CREATE_WORKFLOW_CODE_SAMPLE,
CREATE_WORKFLOW_CODE_SAMPLE_PYTHON,
DELETE_WORKFLOW_CODE_SAMPLE, DELETE_WORKFLOW_CODE_SAMPLE,
GET_RUN_CODE_SAMPLE, GET_RUN_CODE_SAMPLE,
RUN_TASK_CODE_SAMPLE, RUN_TASK_CODE_SAMPLE,
RUN_WORKFLOW_CODE_SAMPLE, RUN_WORKFLOW_CODE_SAMPLE,
UPDATE_WORKFLOW_CODE_SAMPLE, UPDATE_WORKFLOW_CODE_SAMPLE,
UPDATE_WORKFLOW_CODE_SAMPLE_PYTHON,
) )
from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router, legacy_v2_router from skyvern.forge.sdk.routes.routers import base_router, legacy_base_router, legacy_v2_router
from skyvern.forge.sdk.schemas.ai_suggestions import AISuggestionBase, AISuggestionRequest from skyvern.forge.sdk.schemas.ai_suggestions import AISuggestionBase, AISuggestionRequest
@@ -80,6 +82,7 @@ from skyvern.schemas.runs import (
WorkflowRunRequest, WorkflowRunRequest,
WorkflowRunResponse, WorkflowRunResponse,
) )
from skyvern.schemas.workflows import WorkflowRequest
from skyvern.services import run_service, task_v1_service, task_v2_service, workflow_service from skyvern.services import run_service, task_v1_service, task_v2_service, workflow_service
from skyvern.webeye.actions.actions import Action from skyvern.webeye.actions.actions import Action
@@ -437,32 +440,11 @@ async def cancel_run(
response_model=Workflow, response_model=Workflow,
include_in_schema=False, include_in_schema=False,
) )
@base_router.post( async def create_workflow_legacy(
"/workflows",
response_model=Workflow,
tags=["Workflows"],
openapi_extra={
"x-fern-sdk-group-name": "workflows",
"x-fern-sdk-method-name": "create_workflow",
"x-fern-examples": [{"code-samples": [{"sdk": "curl", "code": CREATE_WORKFLOW_CODE_SAMPLE}]}],
},
description="Create a new workflow",
summary="Create a new workflow",
responses={
200: {"description": "Successfully created workflow"},
422: {"description": "Invalid workflow definition"},
},
)
@base_router.post(
"/workflows/",
response_model=Workflow,
include_in_schema=False,
)
async def create_workflow(
request: Request, request: Request,
current_org: Organization = Depends(org_auth_service.get_current_org), current_org: Organization = Depends(org_auth_service.get_current_org),
) -> Workflow: ) -> Workflow:
analytics.capture("skyvern-oss-agent-workflow-create") analytics.capture("skyvern-oss-agent-workflow-create-legacy")
raw_yaml = await request.body() raw_yaml = await request.body()
try: try:
workflow_yaml = yaml.safe_load(raw_yaml) workflow_yaml = yaml.safe_load(raw_yaml)
@@ -481,6 +463,63 @@ async def create_workflow(
raise FailedToCreateWorkflow(str(e)) raise FailedToCreateWorkflow(str(e))
@base_router.post(
"/workflows",
response_model=Workflow,
tags=["Workflows"],
openapi_extra={
"x-fern-sdk-group-name": "workflows",
"x-fern-sdk-method-name": "create_workflow",
"x-fern-examples": [
{
"code-samples": [
{"sdk": "curl", "code": CREATE_WORKFLOW_CODE_SAMPLE},
{"sdk": "python", "code": CREATE_WORKFLOW_CODE_SAMPLE_PYTHON},
]
}
],
},
description="Create a new workflow definition",
summary="Create a new workflow definition",
responses={
200: {"description": "Successfully created workflow"},
422: {"description": "Invalid workflow definition"},
},
)
@base_router.post(
"/workflows/",
response_model=Workflow,
include_in_schema=False,
)
async def create_workflow(
data: WorkflowRequest,
current_org: Organization = Depends(org_auth_service.get_current_org),
) -> Workflow:
analytics.capture("skyvern-oss-agent-workflow-create")
try:
if data.yaml_definition:
workflow_json_from_yaml = yaml.safe_load(data.yaml_definition)
workflow_definition = WorkflowCreateYAMLRequest.model_validate(workflow_json_from_yaml)
elif data.json_definition:
workflow_definition = data.json_definition
else:
raise HTTPException(
status_code=422,
detail="Invalid workflow definition. Workflow should be provided in either yaml or json format.",
)
return await app.WORKFLOW_SERVICE.create_workflow_from_request(
organization=current_org,
request=workflow_definition,
)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
except WorkflowParameterMissingRequiredValue as e:
raise e
except Exception as e:
LOG.error("Failed to create workflow", exc_info=True, organization_id=current_org.organization_id)
raise FailedToCreateWorkflow(str(e))
@legacy_base_router.put( @legacy_base_router.put(
"/workflows/{workflow_id}", "/workflows/{workflow_id}",
openapi_extra={ openapi_extra={
@@ -505,38 +544,7 @@ async def create_workflow(
response_model=Workflow, response_model=Workflow,
include_in_schema=False, include_in_schema=False,
) )
@base_router.post( async def update_workflow_legacy(
"/workflows/{workflow_id}",
response_model=Workflow,
tags=["Workflows"],
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": WorkflowCreateYAMLRequest.model_json_schema()}},
"required": True,
},
"x-fern-sdk-group-name": "workflows",
"x-fern-sdk-method-name": "update_workflow",
"x-fern-examples": [{"code-samples": [{"sdk": "curl", "code": UPDATE_WORKFLOW_CODE_SAMPLE}]}],
},
description="Update a workflow definition",
summary="Update a workflow definition",
responses={
200: {"description": "Successfully updated workflow"},
422: {"description": "Invalid workflow definition"},
},
)
@base_router.post(
"/workflows/{workflow_id}/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": WorkflowCreateYAMLRequest.model_json_schema()}},
"required": True,
},
},
response_model=Workflow,
include_in_schema=False,
)
async def update_workflow(
request: Request, request: Request,
workflow_id: str = Path( workflow_id: str = Path(
..., description="The ID of the workflow to update. Workflow ID starts with `wpid_`.", examples=["wpid_123"] ..., description="The ID of the workflow to update. Workflow ID starts with `wpid_`.", examples=["wpid_123"]
@@ -569,6 +577,78 @@ async def update_workflow(
raise FailedToUpdateWorkflow(workflow_id, f"<{type(e).__name__}: {str(e)}>") raise FailedToUpdateWorkflow(workflow_id, f"<{type(e).__name__}: {str(e)}>")
@base_router.post(
"/workflows/{workflow_id}",
response_model=Workflow,
tags=["Workflows"],
openapi_extra={
"x-fern-sdk-group-name": "workflows",
"x-fern-sdk-method-name": "update_workflow",
"x-fern-examples": [
{
"code-samples": [
{"sdk": "curl", "code": UPDATE_WORKFLOW_CODE_SAMPLE},
{"sdk": "python", "code": UPDATE_WORKFLOW_CODE_SAMPLE_PYTHON},
]
}
],
},
description="Update a workflow definition",
summary="Update a workflow definition",
responses={
200: {"description": "Successfully updated workflow"},
422: {"description": "Invalid workflow definition"},
},
)
@base_router.post(
"/workflows/{workflow_id}/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": WorkflowCreateYAMLRequest.model_json_schema()}},
"required": True,
},
},
response_model=Workflow,
include_in_schema=False,
)
async def update_workflow(
data: WorkflowRequest,
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")
try:
if data.yaml_definition:
workflow_json_from_yaml = yaml.safe_load(data.yaml_definition)
workflow_definition = WorkflowCreateYAMLRequest.model_validate(workflow_json_from_yaml)
elif data.json_definition:
workflow_definition = data.json_definition
else:
raise HTTPException(
status_code=422,
detail="Invalid workflow definition. Workflow should be provided in either yaml or json format.",
)
return await app.WORKFLOW_SERVICE.create_workflow_from_request(
organization=current_org,
request=workflow_definition,
workflow_permanent_id=workflow_id,
)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
except WorkflowParameterMissingRequiredValue as e:
raise e
except Exception as e:
LOG.exception(
"Failed to update workflow",
exc_info=True,
organization_id=current_org.organization_id,
workflow_permanent_id=workflow_id,
)
raise FailedToUpdateWorkflow(workflow_id, f"<{type(e).__name__}: {str(e)}>")
@legacy_base_router.delete( @legacy_base_router.delete(
"/workflows/{workflow_id}", "/workflows/{workflow_id}",
tags=["agent"], tags=["agent"],

View File

@@ -21,280 +21,333 @@ await skyvern.agent.cancel_run(run_id="tsk_v2_123")
""" """
CREATE_WORKFLOW_CODE_SAMPLE = """curl -X POST https://api.skyvern.com/v1/workflows \ CREATE_WORKFLOW_CODE_SAMPLE = """curl -X POST https://api.skyvern.com/v1/workflows \
--header 'x-api-key: {{x-api-key}}' \ --header 'x-api-key: {{x-api-key}}' \
--header 'Content-Type: application/x-yaml' \ --header 'Content-Type: text/plain' \
--data-raw 'title: Invoice Downloading Demo (Jun 13) --data-raw 'title: Contact Forms
description: >- description: Fill the contact form on the website
Login to the website, download all the invoices after a date, email the proxy_location: RESIDENTIAL
invoices webhook_callback_url: https://example.com/webhook
totp_verification_url: https://example.com/totp
persist_browser_session: false
workflow_definition: workflow_definition:
parameters: parameters:
- key: website_url - key: website_url
description: null
parameter_type: workflow parameter_type: workflow
workflow_parameter_type: string workflow_parameter_type: string
- key: credentials default_value: null
parameter_type: bitwarden_login_credential - key: name
bitwarden_client_id_aws_secret_key: SECRET description: null
bitwarden_client_secret_aws_secret_key: SECRET
bitwarden_master_password_aws_secret_key: SECRET
bitwarden_collection_id: SECRET
url_parameter_key: website_url
- key: invoice_retrieval_start_date
parameter_type: workflow parameter_type: workflow
workflow_parameter_type: string workflow_parameter_type: string
- key: smtp_host default_value: null
parameter_type: aws_secret - key: additional_information
aws_key: SKYVERN_SMTP_HOST_AWS_SES description: null
- key: smtp_port parameter_type: workflow
parameter_type: aws_secret workflow_parameter_type: string
aws_key: SKYVERN_SMTP_PORT_AWS_SES default_value: |-
- key: smtp_username Message: I'd love to learn more about your...
parameter_type: aws_secret Phone: 123-456-7890
aws_key: SKYVERN_SMTP_USERNAME_SES Inquiry type: sales
- key: smtp_password Optional Subject: Hello from [Company Here]
parameter_type: aws_secret - key: email
aws_key: SKYVERN_SMTP_PASSWORD_SES description: null
- parameter_type: context parameter_type: workflow
key: order_history_url workflow_parameter_type: string
source_parameter_key: get_order_history_page_url_and_qualifying_order_ids_output default_value: null
- parameter_type: context
key: order_ids
source_parameter_key: get_order_history_page_url_and_qualifying_order_ids_output
- parameter_type: context
key: order_id
source_parameter_key: order_ids
blocks: blocks:
- block_type: task - label: Fill_Out_Contact_Form
label: login continue_on_failure: true
parameter_keys: block_type: navigation
- credentials url: "{{website_url}}"
url: website_url title: Fill_Out_Contact_Form
engine: skyvern-1.0
navigation_goal: >- navigation_goal: >-
If you're not on the login page, navigate to login page and login using the credentials given, and then navigate to the personal account page. First, take actions on promotional popups or cookie prompts that could prevent taking other action on the web page. Then, try to login and navigate to the personal account page. If you fail to login to find the login page or can't login after several trials, terminate. If you're on the personal account page, consider the goal is completed. Find the contact form. Fill out the contact us form and submit it. Your
error_code_mapping: goal is complete when the page says your message has been sent. In the
stuck_with_popups: terminate and return this error if you can't close popups after several tries and can't take the necessary actions on the website because there is a blocking popup on the page case you can't find a contact us form, terminate.
failed_to_login: terminate and return this error if you fail logging in to the page
- block_type: task
label: get_order_history_page_url_and_qualifying_order_ids
parameter_keys:
- invoice_retrieval_start_date
navigation_goal: Find the order history page. If there is no orders after given start date, terminate.
data_extraction_goal: >-
You need to extract the order history page url by looking at the current
page you're on. You need to extract contact emails you see on the page. You also need to extract the order ids for orders that
happened on or after invoice_retrieval_start_date. Make sure to filter
only the orders that happened on or after invoice_retrieval_start_date. You need to compare each order's date with the invoice_download_start_date. You can only include an order in the output if the order's date is after or the same as the invoice_download_start_date.
While comparing dates, first compare year, then month, then day. invoice_retrieval_start_date
is in YYYY-MM-DD format. The dates on the websites may be in different formats, compare accordingly and compare year, date, and month.
error_code_mapping:
failed_to_find_order_history_page: return this error if you can't find the order history page on the website
no_orders_found_after_start_date: return this error if there are no orders after the specified invoice_download_start_date
data_schema:
type: object
properties:
order_history_url:
type: url
description: >-
The exact URL of the order history page. Do not make any
assumptions. Return the URL that's passed along in this context.
contact_emails:
type: array
items:
type: string
description: Contact email for the ecommerce website you're on. If you can't find any return null
date_comparison_scratchpad:
type: string
description: >-
You are supposed to filter the orders that happened on or after the invoice_download_start_date. Think through how you will approach this task step-by-step here. Consider these before starting the comparison:
- What format is the order date in? How can you parse it into a structured format?
- What is the correct way to compare two dates?
- How will you compare the order dates to the invoice_download_start_date?
Write out your thought process before filling out the order_ids field below. Remember, the original date may be in any format, so parse it carefully! The invoice_download_start_date will be an exact date you can directly compare against in the format YYYY-MM-DD.
order_ids: Fill out required fields as best you can using the following
type: array information:
items:
type: object {{name}}
properties:
order_date: {{email}}
type: iso-8601-date-string
order_id: {{additional_information}}
type: string error_code_mapping: null
description: >- max_retries: 0
Return a list of order id strings. Do not return order ids of max_steps_per_run: null
orders that happened before the specified complete_on_download: false
invoice_retrieval_start_date download_suffix: null
- block_type: for_loop parameter_keys: []
label: iterate_over_order_ids totp_identifier: null
loop_over_parameter_key: order_ids totp_verification_url: null
continue_on_failure: true cache_actions: false
loop_blocks: complete_criterion: ""
- block_type: task terminate_criterion: ""
label: download_invoice_for_order include_action_history_in_verification: false
complete_on_download: true - label: Extract_Email
continue_on_failure: true continue_on_failure: false
parameter_keys: block_type: extraction
- order_id url: ""
url: order_history_url title: Extract_Email
navigation_goal: Download the invoice of the order with the given order ID. Make sure to download the invoice for the given order id. If the element tree doesn't have a matching order id, check the screenshots. Complete if you have successfully downloaded the invoice according to action history, if you were able to download it, you'll see download_triggered=True for the last step. If you don't see a way to download an invoice, navigate to the order page if possible. If there's no way to download an invoice terminate. If the text suggests printing, you can assume you can download it. Return click action with download=True if you want to trigger a download. data_extraction_goal: "Extract a company email if available "
error_code_mapping: data_schema: null
not_possible_to_download_invoice: return this error if the website doesn't allow downloading/viewing invoices max_retries: 0
cant_solve_captcha: return this error if captcha isn't solved after multiple retries max_steps_per_run: null
- block_type: upload_to_s3 parameter_keys: []
label: upload_downloaded_files_to_s3 cache_actions: false
path: SKYVERN_DOWNLOAD_DIRECTORY
- block_type: send_email
label: send_email
smtp_host_secret_parameter_key: smtp_host
smtp_port_secret_parameter_key: smtp_port
smtp_username_secret_parameter_key: smtp_username
smtp_password_secret_parameter_key: smtp_password
sender: hello@skyvern.com
recipients:
- founders@skyvern.com
subject: Skyvern - Downloaded Invoices Demo
body: website_url
file_attachments:
- SKYVERN_DOWNLOAD_DIRECTORY
' '
""" """
CREATE_WORKFLOW_CODE_SAMPLE_PYTHON = """
from skyvern import Skyvern
# Create a workflow in JSON format
workflow_definition = {
"title": "Contact Forms Workflow",
"description": "Fill the contact form on the website",
"proxy_location": "RESIDENTIAL",
"webhook_callback_url": "https://example.com/webhook",
"totp_verification_url": "https://example.com/totp",
"totp_identifier": "4155555555",
"workflow_definition": {
"parameters": [
{
"key": "website_url",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
{
"key": "name",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
{
"key": "additional_information",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": "Message: I'd love to learn more about your...\nPhone: 123-456-7890\nInquiry type: sales\nOptional Subject: Hello from [Company Here]",
},
{
"key": "email",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
],
"blocks": [
{
"label": "Fill_Out_Contact_Form",
"continue_on_failure": True,
"block_type": "navigation",
"url": "{{website_url}}",
"title": "Fill_Out_Contact_Form",
"engine": "skyvern-1.0",
"navigation_goal": "Find the contact form. Fill out the contact us form and submit it. Your goal is complete when the page says your message has been sent. In the case you can't find a contact us form, terminate.\n\nFill out required fields as best you can using the following information:\n{{name}}\n{{email}}\n{{additional_information}}",
"error_code_mapping": None,
"max_retries": 0,
"max_steps_per_run": None,
"complete_on_download": False,
"download_suffix": None,
"parameter_keys": [],
"totp_identifier": None,
"totp_verification_url": None,
"cache_actions": False,
"complete_criterion": "",
"terminate_criterion": "",
"include_action_history_in_verification": False,
},
{
"label": "Extract_Email",
"continue_on_failure": False,
"block_type": "extraction",
"url": "",
"title": "Extract_Email",
"data_extraction_goal": "Extract a company email if available ",
"data_schema": None,
"max_retries": 0,
"max_steps_per_run": None,
"parameter_keys": [],
"cache_actions": False,
},
],
},
}
skyvern = Skyvern(api_key="your_api_key")
workflow = await skyvern.workflows.create_workflow(json_definition=workflow_definition)
print(workflow)
"""
UPDATE_WORKFLOW_CODE_SAMPLE = """curl -X POST https://api.skyvern.com/v1/workflows/wpid_123 \ UPDATE_WORKFLOW_CODE_SAMPLE = """curl -X POST https://api.skyvern.com/v1/workflows/wpid_123 \
--header 'x-api-key: {{x-api-key}}' \ --header 'x-api-key: {{x-api-key}}' \
--header 'Content-Type: application/x-yaml' \ --header 'Content-Type: text/plain' \
--data-raw 'title: Invoice Downloading Demo (Jun 13) --data-raw 'title: Contact Forms
description: >- description: Fill the contact form on the website
Login to the website, download all the invoices after a date, email the proxy_location: RESIDENTIAL
invoices webhook_callback_url: https://example.com/webhook
totp_verification_url: https://example.com/totp
persist_browser_session: false
workflow_definition: workflow_definition:
parameters: parameters:
- key: website_url - key: website_url
description: null
parameter_type: workflow parameter_type: workflow
workflow_parameter_type: string workflow_parameter_type: string
- key: credentials default_value: null
parameter_type: bitwarden_login_credential - key: name
bitwarden_client_id_aws_secret_key: SECRET description: null
bitwarden_client_secret_aws_secret_key: SECRET
bitwarden_master_password_aws_secret_key: SECRET
bitwarden_collection_id: SECRET
url_parameter_key: website_url
- key: invoice_retrieval_start_date
parameter_type: workflow parameter_type: workflow
workflow_parameter_type: string workflow_parameter_type: string
- key: smtp_host default_value: null
parameter_type: aws_secret - key: additional_information
aws_key: SKYVERN_SMTP_HOST_AWS_SES description: null
- key: smtp_port parameter_type: workflow
parameter_type: aws_secret workflow_parameter_type: string
aws_key: SKYVERN_SMTP_PORT_AWS_SES default_value: |-
- key: smtp_username Message: I'd love to learn more about your...
parameter_type: aws_secret Phone: 123-456-7890
aws_key: SKYVERN_SMTP_USERNAME_SES Inquiry type: sales
- key: smtp_password Optional Subject: Hello from [Company Here]
parameter_type: aws_secret - key: email
aws_key: SKYVERN_SMTP_PASSWORD_SES description: null
- parameter_type: context parameter_type: workflow
key: order_history_url workflow_parameter_type: string
source_parameter_key: get_order_history_page_url_and_qualifying_order_ids_output default_value: null
- parameter_type: context
key: order_ids
source_parameter_key: get_order_history_page_url_and_qualifying_order_ids_output
- parameter_type: context
key: order_id
source_parameter_key: order_ids
blocks: blocks:
- block_type: task - label: Fill_Out_Contact_Form
label: login continue_on_failure: true
parameter_keys: block_type: navigation
- credentials url: "{{website_url}}"
url: website_url title: Fill_Out_Contact_Form
engine: skyvern-1.0
navigation_goal: >- navigation_goal: >-
If you're not on the login page, navigate to login page and login using the credentials given, and then navigate to the personal account page. First, take actions on promotional popups or cookie prompts that could prevent taking other action on the web page. Then, try to login and navigate to the personal account page. If you fail to login to find the login page or can't login after several trials, terminate. If you're on the personal account page, consider the goal is completed. Find the contact form. Fill out the contact us form and submit it. Your
error_code_mapping: goal is complete when the page says your message has been sent. In the
stuck_with_popups: terminate and return this error if you can't close popups after several tries and can't take the necessary actions on the website because there is a blocking popup on the page case you can't find a contact us form, terminate.
failed_to_login: terminate and return this error if you fail logging in to the page
- block_type: task
label: get_order_history_page_url_and_qualifying_order_ids
parameter_keys:
- invoice_retrieval_start_date
navigation_goal: Find the order history page. If there is no orders after given start date, terminate.
data_extraction_goal: >-
You need to extract the order history page url by looking at the current
page you're on. You need to extract contact emails you see on the page. You also need to extract the order ids for orders that
happened on or after invoice_retrieval_start_date. Make sure to filter
only the orders that happened on or after invoice_retrieval_start_date. You need to compare each order's date with the invoice_download_start_date. You can only include an order in the output if the order's date is after or the same as the invoice_download_start_date.
While comparing dates, first compare year, then month, then day. invoice_retrieval_start_date
is in YYYY-MM-DD format. The dates on the websites may be in different formats, compare accordingly and compare year, date, and month.
error_code_mapping:
failed_to_find_order_history_page: return this error if you can't find the order history page on the website
no_orders_found_after_start_date: return this error if there are no orders after the specified invoice_download_start_date
data_schema:
type: object
properties:
order_history_url:
type: url
description: >-
The exact URL of the order history page. Do not make any
assumptions. Return the URL that's passed along in this context.
contact_emails:
type: array
items:
type: string
description: Contact email for the ecommerce website you're on. If you can't find any return null
date_comparison_scratchpad:
type: string
description: >-
You are supposed to filter the orders that happened on or after the invoice_download_start_date. Think through how you will approach this task step-by-step here. Consider these before starting the comparison:
- What format is the order date in? How can you parse it into a structured format?
- What is the correct way to compare two dates?
- How will you compare the order dates to the invoice_download_start_date?
Write out your thought process before filling out the order_ids field below. Remember, the original date may be in any format, so parse it carefully! The invoice_download_start_date will be an exact date you can directly compare against in the format YYYY-MM-DD.
order_ids: Fill out required fields as best you can using the following
type: array information:
items:
type: object {{name}}
properties:
order_date: {{email}}
type: iso-8601-date-string
order_id: {{additional_information}}
type: string error_code_mapping: null
description: >- max_retries: 0
Return a list of order id strings. Do not return order ids of max_steps_per_run: null
orders that happened before the specified complete_on_download: false
invoice_retrieval_start_date download_suffix: null
- block_type: for_loop parameter_keys: []
label: iterate_over_order_ids totp_identifier: null
loop_over_parameter_key: order_ids totp_verification_url: null
continue_on_failure: true cache_actions: false
loop_blocks: complete_criterion: ""
- block_type: task terminate_criterion: ""
label: download_invoice_for_order include_action_history_in_verification: false
complete_on_download: true - label: Extract_Email
continue_on_failure: true continue_on_failure: false
parameter_keys: block_type: extraction
- order_id url: ""
url: order_history_url title: Extract_Email
navigation_goal: Download the invoice of the order with the given order ID. Make sure to download the invoice for the given order id. If the element tree doesn't have a matching order id, check the screenshots. Complete if you have successfully downloaded the invoice according to action history, if you were able to download it, you'll see download_triggered=True for the last step. If you don't see a way to download an invoice, navigate to the order page if possible. If there's no way to download an invoice terminate. If the text suggests printing, you can assume you can download it. Return click action with download=True if you want to trigger a download. data_extraction_goal: "Extract a company email if available "
error_code_mapping: data_schema: null
not_possible_to_download_invoice: return this error if the website doesn't allow downloading/viewing invoices max_retries: 0
cant_solve_captcha: return this error if captcha isn't solved after multiple retries max_steps_per_run: null
- block_type: upload_to_s3 parameter_keys: []
label: upload_downloaded_files_to_s3 cache_actions: false
path: SKYVERN_DOWNLOAD_DIRECTORY
- block_type: send_email
label: send_email
smtp_host_secret_parameter_key: smtp_host
smtp_port_secret_parameter_key: smtp_port
smtp_username_secret_parameter_key: smtp_username
smtp_password_secret_parameter_key: smtp_password
sender: hello@skyvern.com
recipients:
- founders@skyvern.com
subject: Skyvern - Downloaded Invoices Demo
body: website_url
file_attachments:
- SKYVERN_DOWNLOAD_DIRECTORY
' '
""" """
UPDATE_WORKFLOW_CODE_SAMPLE_PYTHON = """
from skyvern import Skyvern
updated_workflow_definition = {
"title": "Updated Contact Forms Workflow",
"description": "Fill the contact form on the website",
"proxy_location": "RESIDENTIAL",
"webhook_callback_url": "https://example.com/webhook",
"totp_verification_url": "https://example.com/totp",
"totp_identifier": "4155555555",
"workflow_definition": {
"parameters": [
{
"key": "website_url",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
{
"key": "name",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
{
"key": "additional_information",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": "Message: I'd love to learn more about your...\nPhone: 123-456-7890\nInquiry type: sales\nOptional Subject: Hello from [Company Here]",
},
{
"key": "email",
"description": None,
"parameter_type": "workflow",
"workflow_parameter_type": "string",
"default_value": None,
},
],
"blocks": [
{
"label": "Fill_Out_Contact_Form",
"continue_on_failure": True,
"block_type": "navigation",
"url": "{{website_url}}",
"title": "Fill_Out_Contact_Form",
"engine": "skyvern-1.0",
"navigation_goal": "Find the contact form. Fill out the contact us form and submit it. Your goal is complete when the page says your message has been sent. In the case you can't find a contact us form, terminate.\n\nFill out required fields as best you can using the following information:\n{{name}}\n{{email}}\n{{additional_information}}",
"error_code_mapping": None,
"max_retries": 0,
"max_steps_per_run": None,
"complete_on_download": False,
"download_suffix": None,
"parameter_keys": [],
"totp_identifier": None,
"totp_verification_url": None,
"cache_actions": False,
"complete_criterion": "",
"terminate_criterion": "",
"include_action_history_in_verification": False,
},
{
"label": "Extract_Email",
"continue_on_failure": False,
"block_type": "extraction",
"url": "",
"title": "Extract_Email",
"data_extraction_goal": "Extract a company email if available ",
"data_schema": None,
"max_retries": 0,
"max_steps_per_run": None,
"parameter_keys": [],
"cache_actions": False,
},
],
},
}
skyvern = Skyvern(api_key="your_api_key")
workflow = await skyvern.workflows.update_workflow(workflow_id="wpid_123", json_definition=updated_workflow_definition)
print(workflow)
"""
DELETE_WORKFLOW_CODE_SAMPLE = """from skyvern import Skyvern DELETE_WORKFLOW_CODE_SAMPLE = """from skyvern import Skyvern
skyvern = Skyvern(api_key="your_api_key") skyvern = Skyvern(api_key="your_api_key")

View File

@@ -0,0 +1,14 @@
from pydantic import BaseModel, Field
from skyvern.forge.sdk.workflow.models.yaml import WorkflowCreateYAMLRequest
class WorkflowRequest(BaseModel):
json_definition: WorkflowCreateYAMLRequest | None = Field(
default=None,
description="Workflow definition in JSON format",
)
yaml_definition: str | None = Field(
default=None,
description="Workflow definition in YAML format",
)