Better handle duplicate elements (#351)
This commit is contained in:
@@ -49,6 +49,12 @@ from skyvern.webeye.scraper.scraper import ElementTreeFormat, ScrapedPage, scrap
|
|||||||
LOG = structlog.get_logger()
|
LOG = structlog.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class ActionLinkedNode:
|
||||||
|
def __init__(self, action: ActionTypeUnion) -> None:
|
||||||
|
self.action = action
|
||||||
|
self.next: ActionLinkedNode | None = None
|
||||||
|
|
||||||
|
|
||||||
class ForgeAgent:
|
class ForgeAgent:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
if SettingsManager.get_settings().ADDITIONAL_MODULES:
|
if SettingsManager.get_settings().ADDITIONAL_MODULES:
|
||||||
@@ -457,16 +463,59 @@ class ForgeAgent:
|
|||||||
# of an exception, we can still see all the actions
|
# of an exception, we can still see all the actions
|
||||||
detailed_agent_step_output.actions_and_results = [(action, []) for action in actions]
|
detailed_agent_step_output.actions_and_results = [(action, []) for action in actions]
|
||||||
|
|
||||||
web_action_element_ids = set()
|
# build a linked action chain by the action_idx
|
||||||
|
action_linked_list: list[ActionLinkedNode] = []
|
||||||
|
element_id_to_action_index: dict[int, int] = dict()
|
||||||
for action_idx, action in enumerate(actions):
|
for action_idx, action in enumerate(actions):
|
||||||
|
node = ActionLinkedNode(action=action)
|
||||||
|
action_linked_list.append(node)
|
||||||
|
|
||||||
|
previous_action_idx = element_id_to_action_index.get(action.element_id)
|
||||||
|
if previous_action_idx is not None:
|
||||||
|
previous_node = action_linked_list[previous_action_idx]
|
||||||
|
previous_node.next = node
|
||||||
|
|
||||||
|
element_id_to_action_index[action.element_id] = action_idx
|
||||||
|
|
||||||
|
element_id_to_last_action: dict[int, int] = dict()
|
||||||
|
for action_idx, action_node in enumerate(action_linked_list):
|
||||||
|
action = action_node.action
|
||||||
if isinstance(action, WebAction):
|
if isinstance(action, WebAction):
|
||||||
if action.element_id in web_action_element_ids:
|
previous_action_idx = element_id_to_last_action.get(action.element_id)
|
||||||
LOG.error(
|
if previous_action_idx is not None:
|
||||||
"Duplicate action element id. Action handling stops",
|
LOG.warning(
|
||||||
|
"Duplicate action element id.",
|
||||||
|
task_id=task.task_id,
|
||||||
|
step_id=step.step_id,
|
||||||
|
step_order=step.order,
|
||||||
action=action,
|
action=action,
|
||||||
)
|
)
|
||||||
break
|
|
||||||
web_action_element_ids.add(action.element_id)
|
# if the last action succeeded, then skip handling
|
||||||
|
previous_action, previous_result = detailed_agent_step_output.actions_and_results[
|
||||||
|
previous_action_idx
|
||||||
|
]
|
||||||
|
if len(previous_result) > 0 and previous_result[-1].success:
|
||||||
|
LOG.info(
|
||||||
|
"Previous action succeeded, so skip this one.",
|
||||||
|
task_id=task.task_id,
|
||||||
|
step_id=step.step_id,
|
||||||
|
step_order=step.order,
|
||||||
|
previouse_action=previous_action,
|
||||||
|
previouse_result=previous_result,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
LOG.warning(
|
||||||
|
"Previous action failed, so handle this action.",
|
||||||
|
task_id=task.task_id,
|
||||||
|
step_id=step.step_id,
|
||||||
|
step_order=step.order,
|
||||||
|
previouse_action=previous_action,
|
||||||
|
previouse_result=previous_result,
|
||||||
|
)
|
||||||
|
|
||||||
|
element_id_to_last_action[action.element_id] = action_idx
|
||||||
|
|
||||||
self.async_operation_pool.run_operation(task.task_id, AgentPhase.action)
|
self.async_operation_pool.run_operation(task.task_id, AgentPhase.action)
|
||||||
results = await ActionHandler.handle_action(scraped_page, task, step, browser_state, action)
|
results = await ActionHandler.handle_action(scraped_page, task, step, browser_state, action)
|
||||||
@@ -505,6 +554,20 @@ class ForgeAgent:
|
|||||||
# stop executing the rest actions
|
# stop executing the rest actions
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
if action_node.next is not None:
|
||||||
|
LOG.warning(
|
||||||
|
"Action failed, but have duplicated element id in the action list. Continue excuting.",
|
||||||
|
task_id=task.task_id,
|
||||||
|
step_id=step.step_id,
|
||||||
|
step_order=step.order,
|
||||||
|
step_retry=step.retry_index,
|
||||||
|
action_idx=action_idx,
|
||||||
|
action=action,
|
||||||
|
next_action=action_node.next.action,
|
||||||
|
action_result=results,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"Action failed, marking step as failed",
|
"Action failed, marking step as failed",
|
||||||
task_id=task.task_id,
|
task_id=task.task_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user