def step(self, state: State) -> Action:
        """Performs one step using the VisualBrowsingAgent.

        This includes gathering information on previous steps and prompting the model to make a browsing command to execute.

        Parameters:
        - state (State): used to get updated info

        Returns:
        - BrowseInteractiveAction(browsergym_command) - BrowserGym commands to run
        - MessageAction(content) - Message action to run (e.g. ask for clarification)
        - AgentFinishAction() - end the interaction
        """
        messages: list[Message] = []
        prev_actions = []
        cur_axtree_txt = ''
        error_prefix = ''
        focused_element = ''
        tabs = ''
        last_obs = None
        last_action = None
        set_of_marks = None  # Initialize set_of_marks to None

        if len(state.view) == 1:
            # for visualwebarena, webarena and miniwob++ eval, we need to retrieve the initial observation already in browser env
            # initialize and retrieve the first observation by issuing an noop OP
            # For non-benchmark browsing, the browser env starts with a blank page, and the agent is expected to first navigate to desired websites
            return BrowseInteractiveAction(browser_actions='noop(1000)', return_axtree=True)

        for event in state.view:
            if isinstance(event, BrowseInteractiveAction):
                prev_actions.append(event)
                last_action = event
            elif isinstance(event, MessageAction) and event.source == EventSource.AGENT:
                # agent has responded, task finished.
                return AgentFinishAction(outputs={'content': event.content})
            elif isinstance(event, Observation):
                # Only process BrowserOutputObservation and skip other observation types
                if not isinstance(event, BrowserOutputObservation):
                    continue
                last_obs = event

        if len(prev_actions) >= 1:  # ignore noop()
            prev_actions = prev_actions[1:]  # remove the first noop action

        # if the final BrowserInteractiveAction exec BrowserGym's send_msg_to_user,
        # we should also send a message back to the user in OpenHands and call it a day
        if (
            isinstance(last_action, BrowseInteractiveAction)
            and last_action.browsergym_send_msg_to_user
        ):
            return MessageAction(last_action.browsergym_send_msg_to_user)

        history_prompt = get_history_prompt(prev_actions)
        if isinstance(last_obs, BrowserOutputObservation):
            if last_obs.error:
                # add error recovery prompt prefix
                error_prefix = get_error_prefix(last_obs)
                if len(error_prefix) > 0:
                    self.error_accumulator += 1
                    if self.error_accumulator > 5:
                        return MessageAction(
                            'Too many errors encountered. Task failed.'
                        )
            focused_element = '## Focused element:\nNone\n'
            if last_obs.focused_element_bid is not None:
                focused_element = (
                    f"## Focused element:\nbid='{last_obs.focused_element_bid}'\n"
                )
            tabs = get_tabs(last_obs)
            try:
                # IMPORTANT: keep AX Tree of full webpage, add visible and clickable tags
                cur_axtree_txt = flatten_axtree_to_str(
                    last_obs.axtree_object,
                    extra_properties=last_obs.extra_element_properties,
                    with_visible=True,
                    with_clickable=True,
                    with_center_coords=False,
                    with_bounding_box_coords=False,
                    filter_visible_only=False,
                    filter_with_bid_only=False,
                    filter_som_only=False,
                )
                cur_axtree_txt = get_axtree(axtree_txt=cur_axtree_txt)
            except Exception as e:
                logger.error(
                    'Error when trying to process the accessibility tree: %s', e
                )
                return MessageAction('Error encountered when browsing.')
            set_of_marks = last_obs.set_of_marks
        goal, image_urls = state.get_current_user_intent()

        if goal is None:
            goal = state.inputs['task']
        goal_txt, goal_images = create_goal_prompt(goal, image_urls)
        observation_txt, som_screenshot = create_observation_prompt(
            cur_axtree_txt, tabs, focused_element, error_prefix, set_of_marks
        )
        human_prompt: list[TextContent | ImageContent] = [
            TextContent(type='text', text=goal_txt)
        ]
        if len(goal_images) > 0:
            human_prompt.append(ImageContent(image_urls=goal_images))
        human_prompt.append(TextContent(type='text', text=observation_txt))
        if som_screenshot is not None:
            human_prompt.append(ImageContent(image_urls=[som_screenshot]))
        remaining_content = f"""
{history_prompt}\
{self.action_prompt}\
{self.hints}\
{self.abstract_example}\
{self.concrete_example}\
"""
        human_prompt.append(TextContent(type='text', text=remaining_content))

        system_msg = """\
You are an agent trying to solve a web task based on the content of the page and user instructions. You can interact with the page and explore, and send messages to the user when you finish the task. Each time you submit an action it will be sent to the browser and you will receive a new page.
""".strip()

        messages.append(Message(role='system', content=[TextContent(text=system_msg)]))
        messages.append(Message(role='user', content=human_prompt))

        flat_messages = self.llm.format_messages_for_llm(messages)

        response = self.llm.completion(
            messages=flat_messages,
            temperature=0.0,
            stop=[')```', ')\n```'],
        )

        return self.response_parser.parse(response)
Performs one step using the VisualBrowsingAgent.

        This includes gathering information on previous steps and prompting the model to make a browsing command to execute.

        Parameters:
        - state (State): used to get updated info

        Returns:
        - BrowseInteractiveAction(browsergym_command) - BrowserGym commands to run
        - MessageAction(content) - Message action to run (e.g. ask for clarification)
        - AgentFinishAction() - end the interaction
        
openhands/agenthub/visualbrowsing_agent/visualbrowsing_agent.py