run script with workflow block run, task, step and artifacts built (#3234)
This commit is contained in:
@@ -777,7 +777,10 @@ def _build_goto_statement(block: dict[str, Any]) -> cst.SimpleStatementLine:
|
||||
|
||||
def _build_run_fn(blocks: list[dict[str, Any]], wf_req: dict[str, Any]) -> FunctionDef:
|
||||
body = [
|
||||
cst.parse_statement("page, context = await skyvern.setup(parameters.model_dump())"),
|
||||
cst.parse_statement(
|
||||
"parameters = parameters.model_dump() if isinstance(parameters, WorkflowParameters) else parameters"
|
||||
),
|
||||
cst.parse_statement("page, context = await skyvern.setup(parameters)"),
|
||||
]
|
||||
|
||||
for block in blocks:
|
||||
|
||||
@@ -13,9 +13,11 @@ from skyvern.config import settings
|
||||
from skyvern.forge import app
|
||||
from skyvern.forge.prompts import prompt_engine
|
||||
from skyvern.forge.sdk.api.files import download_file
|
||||
from skyvern.forge.sdk.artifact.models import ArtifactType
|
||||
from skyvern.forge.sdk.core import skyvern_context
|
||||
from skyvern.webeye.actions import handler_utils
|
||||
from skyvern.webeye.actions.action_types import ActionType
|
||||
from skyvern.webeye.actions.actions import Action
|
||||
from skyvern.webeye.scraper.scraper import ScrapedPage, scrape_website
|
||||
|
||||
|
||||
@@ -85,9 +87,8 @@ class SkyvernPage:
|
||||
"""
|
||||
Decorator to record the action call.
|
||||
|
||||
TODOs:
|
||||
- generate action record in db pre action
|
||||
- generate screenshot post action
|
||||
Auto-creates action records in DB before action execution
|
||||
and screenshot artifacts after action execution.
|
||||
"""
|
||||
|
||||
def decorator(fn: Callable) -> Callable:
|
||||
@@ -100,18 +101,33 @@ class SkyvernPage:
|
||||
) -> Any:
|
||||
meta = ActionMetadata(intention, data)
|
||||
call = ActionCall(action, args, kwargs, meta)
|
||||
|
||||
# Auto-create action before execution
|
||||
action_record = await skyvern_page._create_action_before_execution(
|
||||
action_type=action, intention=intention, data=data
|
||||
)
|
||||
|
||||
try:
|
||||
call.result = await fn(
|
||||
skyvern_page, *args, intention=intention, data=data, **kwargs
|
||||
) # real driver call
|
||||
|
||||
# Note: Action status would be updated to completed here if update method existed
|
||||
|
||||
return call.result
|
||||
except Exception as e:
|
||||
call.error = e
|
||||
|
||||
# Note: Action status would be updated to failed here if update method existed
|
||||
|
||||
# LLM fallback hook could go here ...
|
||||
raise
|
||||
finally:
|
||||
skyvern_page._record(call)
|
||||
|
||||
# Auto-create screenshot artifact after execution
|
||||
await skyvern_page._create_screenshot_after_execution(action_record)
|
||||
|
||||
return wrapper
|
||||
|
||||
return decorator
|
||||
@@ -119,6 +135,73 @@ class SkyvernPage:
|
||||
async def goto(self, url: str) -> None:
|
||||
await self.page.goto(url)
|
||||
|
||||
async def _create_action_before_execution(
|
||||
self, action_type: ActionType, intention: str = "", data: str | dict[str, Any] = ""
|
||||
) -> Action | None:
|
||||
"""Create an action record in the database before execution if task_id and step_id are available."""
|
||||
try:
|
||||
context = skyvern_context.current()
|
||||
if not context or not context.task_id or not context.step_id:
|
||||
return None
|
||||
|
||||
# Create action record
|
||||
action = Action(
|
||||
action_type=action_type,
|
||||
organization_id=context.organization_id,
|
||||
workflow_run_id=context.workflow_run_id,
|
||||
task_id=context.task_id,
|
||||
step_id=context.step_id,
|
||||
step_order=0, # Will be updated by the system if needed
|
||||
action_order=0, # Will be updated by the system if needed
|
||||
intention=intention,
|
||||
reasoning=f"Auto-generated action for {action_type.value}",
|
||||
)
|
||||
|
||||
created_action = await app.DATABASE.create_action(action)
|
||||
return created_action
|
||||
|
||||
except Exception:
|
||||
# If action creation fails, don't block the actual action execution
|
||||
return None
|
||||
|
||||
async def _create_screenshot_after_execution(self, action_record: Action | None = None) -> None:
|
||||
"""Create a screenshot artifact after action execution if task_id and step_id are available."""
|
||||
try:
|
||||
context = skyvern_context.ensure_context()
|
||||
if not context or not context.task_id or not context.step_id:
|
||||
return
|
||||
|
||||
# Get browser state and take screenshot
|
||||
browser_state = await app.BROWSER_MANAGER.get_for_script()
|
||||
if not browser_state:
|
||||
return
|
||||
|
||||
screenshot = await browser_state.take_fullpage_screenshot(
|
||||
use_playwright_fullpage=app.EXPERIMENTATION_PROVIDER.is_feature_enabled_cached(
|
||||
"ENABLE_PLAYWRIGHT_FULLPAGE",
|
||||
context.workflow_run_id or context.task_id,
|
||||
properties={"organization_id": context.organization_id},
|
||||
)
|
||||
)
|
||||
|
||||
if screenshot:
|
||||
# Create a minimal Step object for artifact creation
|
||||
step = await app.DATABASE.get_step(
|
||||
context.task_id, context.step_id, organization_id=context.organization_id
|
||||
)
|
||||
if not step:
|
||||
return
|
||||
|
||||
await app.ARTIFACT_MANAGER.create_artifact(
|
||||
step=step,
|
||||
artifact_type=ArtifactType.SCREENSHOT_ACTION,
|
||||
data=screenshot,
|
||||
)
|
||||
|
||||
except Exception:
|
||||
# If screenshot creation fails, don't block execution
|
||||
pass
|
||||
|
||||
######### Public Interfaces #########
|
||||
@action_wrap(ActionType.CLICK)
|
||||
async def click(self, xpath: str, intention: str | None = None, data: str | dict[str, Any] | None = None) -> None:
|
||||
|
||||
Reference in New Issue
Block a user