fix input text action with no text in GET steps API (#421)
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import abc
|
||||
from enum import StrEnum
|
||||
from typing import Any, Dict, List
|
||||
from typing import Any, Dict
|
||||
|
||||
import structlog
|
||||
from deprecation import deprecated
|
||||
@@ -27,17 +26,6 @@ class ActionType(StrEnum):
|
||||
SOLVE_CAPTCHA = "solve_captcha"
|
||||
TERMINATE = "terminate"
|
||||
COMPLETE = "complete"
|
||||
# Note: Remember to update ActionTypeUnion with new actions
|
||||
|
||||
|
||||
class Action(BaseModel):
|
||||
action_type: ActionType
|
||||
description: str | None = None
|
||||
reasoning: str | None = None
|
||||
|
||||
|
||||
class WebAction(Action, abc.ABC):
|
||||
element_id: str
|
||||
|
||||
|
||||
class UserDefinedError(BaseModel):
|
||||
@@ -46,8 +34,41 @@ class UserDefinedError(BaseModel):
|
||||
confidence_float: float = Field(..., ge=0, le=1)
|
||||
|
||||
|
||||
class DecisiveAction(Action, abc.ABC):
|
||||
errors: List[UserDefinedError] = []
|
||||
class SelectOption(BaseModel):
|
||||
label: str | None
|
||||
value: str | None
|
||||
index: int | None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"SelectOption(label={self.label}, value={self.value}, index={self.index})"
|
||||
|
||||
|
||||
class Action(BaseModel):
|
||||
action_type: ActionType
|
||||
description: str | None = None
|
||||
reasoning: str | None = None
|
||||
element_id: str | None = None
|
||||
|
||||
# DecisiveAction (CompleteAction, TerminateAction) fields
|
||||
errors: list[UserDefinedError] | None = None
|
||||
data_extraction_goal: str | None = None
|
||||
|
||||
# WebAction fields
|
||||
file_name: str | None = None
|
||||
file_url: str | None = None
|
||||
download: bool | None = None
|
||||
is_upload_file_tag: bool | None = None
|
||||
text: str | None = None
|
||||
option: SelectOption | None = None
|
||||
is_checked: bool | None = None
|
||||
|
||||
|
||||
class WebAction(Action):
|
||||
element_id: str
|
||||
|
||||
|
||||
class DecisiveAction(Action):
|
||||
errors: list[UserDefinedError] = []
|
||||
|
||||
|
||||
class ClickAction(WebAction):
|
||||
@@ -55,6 +76,9 @@ class ClickAction(WebAction):
|
||||
file_url: str | None = None
|
||||
download: bool = False
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"ClickAction(element_id={self.element_id}, file_url={self.file_url}, download={self.download})"
|
||||
|
||||
|
||||
class InputTextAction(WebAction):
|
||||
action_type: ActionType = ActionType.INPUT_TEXT
|
||||
@@ -90,15 +114,6 @@ class SolveCaptchaAction(Action):
|
||||
action_type: ActionType = ActionType.SOLVE_CAPTCHA
|
||||
|
||||
|
||||
class SelectOption(BaseModel):
|
||||
label: str | None
|
||||
value: str | None
|
||||
index: int | None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"SelectOption(label={self.label}, value={self.value}, index={self.index})"
|
||||
|
||||
|
||||
class SelectOptionAction(WebAction):
|
||||
action_type: ActionType = ActionType.SELECT_OPTION
|
||||
option: SelectOption
|
||||
@@ -221,8 +236,8 @@ def parse_action(action: Dict[str, Any], data_extraction_goal: str | None = None
|
||||
raise UnsupportedActionType(action_type=action_type)
|
||||
|
||||
|
||||
def parse_actions(task: Task, json_response: List[Dict[str, Any]]) -> List[Action]:
|
||||
actions: List[Action] = []
|
||||
def parse_actions(task: Task, json_response: list[Dict[str, Any]]) -> list[Action]:
|
||||
actions: list[Action] = []
|
||||
for action in json_response:
|
||||
try:
|
||||
action_instance = parse_action(action=action, data_extraction_goal=task.data_extraction_goal)
|
||||
@@ -257,7 +272,6 @@ def parse_actions(task: Task, json_response: List[Dict[str, Any]]) -> List[Actio
|
||||
raw_action=action,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
return actions
|
||||
|
||||
|
||||
@@ -268,20 +282,3 @@ class ScrapeResult(BaseModel):
|
||||
"""
|
||||
|
||||
scraped_data: dict[str, Any] | list[dict[str, Any]]
|
||||
|
||||
|
||||
# https://blog.devgenius.io/deserialize-child-classes-with-pydantic-that-gonna-work-784230e1cf83
|
||||
ActionTypeUnion = (
|
||||
ClickAction
|
||||
| InputTextAction
|
||||
| UploadFileAction
|
||||
# Deprecated
|
||||
# | DownloadFileAction
|
||||
| SelectOptionAction
|
||||
| CheckboxAction
|
||||
| WaitAction
|
||||
| NullAction
|
||||
| SolveCaptchaAction
|
||||
| TerminateAction
|
||||
| CompleteAction
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
from skyvern.forge.sdk.settings_manager import SettingsManager
|
||||
from skyvern.webeye.actions.actions import Action, ActionTypeUnion, DecisiveAction, UserDefinedError
|
||||
from skyvern.webeye.actions.actions import Action, DecisiveAction, UserDefinedError
|
||||
from skyvern.webeye.actions.responses import ActionResult
|
||||
from skyvern.webeye.scraper.scraper import ScrapedPage
|
||||
|
||||
@@ -18,7 +18,7 @@ class AgentStepOutput(BaseModel):
|
||||
# Will be deprecated once we move to the new format below
|
||||
action_results: list[ActionResult] | None = None
|
||||
# Nullable for backwards compatibility, once backfill is done, this won't be nullable anymore
|
||||
actions_and_results: list[tuple[ActionTypeUnion, list[ActionResult]]] | None = None
|
||||
actions_and_results: list[tuple[Action, list[ActionResult]]] | None = None
|
||||
errors: list[UserDefinedError] = []
|
||||
|
||||
def __repr__(self) -> str:
|
||||
@@ -38,7 +38,7 @@ class DetailedAgentStepOutput(BaseModel):
|
||||
llm_response: dict[str, Any] | None
|
||||
actions: list[Action] | None
|
||||
action_results: list[ActionResult] | None
|
||||
actions_and_results: list[tuple[ActionTypeUnion, list[ActionResult]]] | None
|
||||
actions_and_results: list[tuple[Action, list[ActionResult]]] | None
|
||||
|
||||
class Config:
|
||||
exclude = ["scraped_page", "extract_action_prompt"]
|
||||
|
||||
Reference in New Issue
Block a user