Skip to content

Browsing actions

conatus.actions.preloaded.browsing.browser_start conatus-action

browser_start(
    *, headless: bool = True, url: str | None = None
) -> SimpleBrowser
This function is an Action

You can call browser_start just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_start has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Start a browser.

PARAMETER DESCRIPTION
headless

Whether to run the browser in headless mode. Defaults to True.

TYPE: bool DEFAULT: True

url

The URL to go to.

TYPE: str | None DEFAULT: None

RETURNS DESCRIPTION
SimpleBrowser

The browser.

Source code in conatus/actions/preloaded/browsing.py
@action
def browser_start(
    *, headless: bool = True, url: str | None = None
) -> SimpleBrowser:
    """Start a browser.

    Args:
        headless: Whether to run the browser in headless mode. Defaults to
            `True`.
        url: The URL to go to.

    Returns:
        (SimpleBrowser): The browser.
    """
    browser = SimpleBrowser(headless=headless)
    if url:
        browser = browser.goto(url)
    return browser

conatus.actions.preloaded.browsing.browser_start_visible conatus-action

browser_start_visible() -> SimpleBrowser
This function is an Action

You can call browser_start_visible just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_start_visible has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Start a browser that is visible.

RETURNS DESCRIPTION
SimpleBrowser

The browser.

Source code in conatus/actions/preloaded/browsing.py
@action
def browser_start_visible() -> SimpleBrowser:  # pragma: no cover
    """Start a browser that is visible.

    Returns:
        (SimpleBrowser): The browser.
    """
    return SimpleBrowser(headless=False)

conatus.actions.preloaded.browsing.browser_goto conatus-action

browser_goto(browser: SimpleBrowser, url: str) -> None
This function is an Action

You can call browser_goto just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_goto has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Go to a URL.

Ultimately, if you provide a URL that is invalid, the browser will throw an error.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

url

The URL to go to.

TYPE: str

Source code in conatus/actions/preloaded/browsing.py
@action(force_update_on="browser")
def browser_goto(browser: SimpleBrowser, url: str) -> None:
    """Go to a URL.

    Ultimately, if you provide a URL that is invalid, the browser will
    throw an error.

    Args:
        browser: The browser to use.
        url: The URL to go to.
    """
    _ = browser.goto(url)

conatus.actions.preloaded.browsing.browser_close conatus-action

browser_close(browser: SimpleBrowser) -> None
This function is an Action

You can call browser_close just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_close has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Close the browser.

PARAMETER DESCRIPTION
browser

The browser to close.

TYPE: SimpleBrowser

Source code in conatus/actions/preloaded/browsing.py
@action
def browser_close(browser: SimpleBrowser) -> None:
    """Close the browser.

    Args:
        browser: The browser to close.
    """
    _ = browser.close()

conatus.actions.preloaded.browsing.browser_get_page_title conatus-action

browser_get_page_title(browser: SimpleBrowser) -> str
This function is an Action

You can call browser_get_page_title just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_get_page_title has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Get the title of the current page.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

RETURNS DESCRIPTION
str

The title of the current page.

Source code in conatus/actions/preloaded/browsing.py
@action
def browser_get_page_title(browser: SimpleBrowser) -> str:
    """Get the title of the current page.

    Args:
        browser: The browser to use.

    Returns:
        (str): The title of the current page.
    """
    return browser.page_title

conatus.actions.preloaded.browsing.browser_page_html conatus-action

browser_page_html(browser: SimpleBrowser) -> HTML
This function is an Action

You can call browser_page_html just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_page_html has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Grab the browser's fully-rendered HTML as a parseable object.

PARAMETER DESCRIPTION
browser

The browser whose current page to capture.

TYPE: SimpleBrowser

RETURNS DESCRIPTION
HTML

The rendered page.

Source code in conatus/actions/preloaded/browsing.py
@action(force_update_on="browser")
def browser_page_html(browser: SimpleBrowser) -> HTML:
    """Grab the browser's fully-rendered HTML as a parseable object.

    Args:
        browser: The browser whose current page to capture.

    Returns:
        (HTML): The rendered page.
    """
    return HTML(
        soup=BeautifulSoup(browser.page_html(), "html.parser"),
        url=browser.page_url,
    )

conatus.actions.preloaded.browsing.list_clickable_nodes conatus-action

list_clickable_nodes(
    browser: SimpleBrowser, min_text_length: int = 0
) -> str
This function is an Action

You can call list_clickable_nodes just like a regular function, but note that it is actually a Action object.

This means that:

  • list_clickable_nodes has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

List the current page's clickable nodes as a readable text table.

Gives the model a reliable handle on what it can click. Each row is [id] <tag> 'text' · key=val, where id is exactly the id accepted by add_nodes_to_set and browser_click_node . Reading these ids off this table is more reliable than reading the numbers off the screenshot.

PARAMETER DESCRIPTION
browser

The browser whose current page to inspect.

TYPE: SimpleBrowser

min_text_length

If greater than 0, omit nodes whose visible text is shorter than this -- a generic way to hide icon-only / chrome links. Defaults to 0, which lists every clickable node.

TYPE: int DEFAULT: 0

RETURNS DESCRIPTION
str

A newline-separated table of clickable nodes, or a notice if none qualify.

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def list_clickable_nodes(
    browser: SimpleBrowser, min_text_length: int = 0
) -> str:
    """List the current page's clickable nodes as a readable text table.

    Gives the model a reliable handle on what it can click. Each row is
    `[id] <tag> 'text' · key=val`, where `id` is exactly the id accepted by
    [`add_nodes_to_set`][conatus.actions.preloaded.browsing.add_nodes_to_set]
    and [`browser_click_node`
    ][conatus.actions.preloaded.browsing.browser_click_node]. Reading these ids
    off this table is more reliable than reading the numbers off the screenshot.

    Args:
        browser: The browser whose current page to inspect.
        min_text_length: If greater than 0, omit nodes whose visible text is
            shorter than this -- a generic way to hide icon-only / chrome links.
            Defaults to 0, which lists every clickable node.

    Returns:
        (str): A newline-separated table of clickable nodes, or a notice if
            none qualify.
    """
    clickable = browser.page.last_step.clickable_elements
    rows = [
        _clickable_node_row(node_id, node)
        for node_id, node in sorted(clickable.items())
        if len(" ".join(node.inner_text.split())) >= min_text_length
    ]
    if not rows:
        return "(no clickable nodes detected on the current page)"
    header = f"{len(rows)} clickable nodes (ids match add_nodes_to_set):"
    return header + "\n" + "\n".join(rows)

conatus.actions.preloaded.browsing.browser_do_nothing conatus-action

browser_do_nothing(
    browser: SimpleBrowser, *, seconds: float | None = None
) -> None
This function is an Action

You can call browser_do_nothing just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_do_nothing has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Do nothing.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

seconds

The number of seconds to wait.

TYPE: float | None DEFAULT: None

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_do_nothing(
    browser: SimpleBrowser, *, seconds: float | None = None
) -> None:
    """Do nothing.

    Args:
        browser: The browser to use.
        seconds: The number of seconds to wait.
    """
    if seconds is not None:
        time.sleep(seconds)
    _ = browser

conatus.actions.preloaded.browsing.browser_click conatus-action

browser_click(
    browser: SimpleBrowser,
    x: float,
    y: float,
    *,
    button: ExtendedMouseButton = "left",
    click_count: int = 1
) -> None
This function is an Action

You can call browser_click just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_click has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Click on an element at a given position.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

x

The x coordinate of the element to click.

TYPE: float

y

The y coordinate of the element to click.

TYPE: float

button

The button to click on. Defaults to "left".

TYPE: ExtendedMouseButton DEFAULT: 'left'

click_count

The number of clicks to perform. Defaults to 1.

TYPE: int DEFAULT: 1

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_click(
    browser: SimpleBrowser,
    x: float,
    y: float,
    *,
    button: ExtendedMouseButton = "left",
    click_count: int = 1,
) -> None:
    """Click on an element at a given position.

    Args:
        browser: The browser to use.
        x: The x coordinate of the element to click.
        y: The y coordinate of the element to click.
        button: The button to click on. Defaults to `"left"`.
        click_count: The number of clicks to perform. Defaults to `1`.
    """
    _ = browser.click(x, y, button=button, click_count=click_count)

conatus.actions.preloaded.browsing.browser_click_node conatus-action

browser_click_node(
    browser: SimpleBrowser, node_id: int
) -> None
This function is an Action

You can call browser_click_node just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_click_node has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Click on a node.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

node_id

The id of the node to click on.

TYPE: int

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_click_node(browser: SimpleBrowser, node_id: int) -> None:
    """Click on a node.

    Args:
        browser: The browser to use.
        node_id: The id of the node to click on.
    """
    _ = browser.click_node(node_id)

conatus.actions.preloaded.browsing.add_nodes_to_set conatus-action

add_nodes_to_set(
    browser: SimpleBrowser,
    node_ids: set[int],
    existing_set: Existing[set[DOMNode]] | None = None,
) -> Existing[set[DOMNode]]
This function is an Action

You can call add_nodes_to_set just like a regular function, but note that it is actually a Action object.

This means that:

  • add_nodes_to_set has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Add nodes to a (potentially pre-existing) set.

Ids that aren't currently clickable on the page are silently skipped rather than raising.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

node_ids

The ids of the nodes to add.

TYPE: set[int]

existing_set

The set to add the nodes to. If not provided, a new set will be created.

TYPE: Existing[set[DOMNode]] | None DEFAULT: None

RETURNS DESCRIPTION
set[DOMNode]

The set of nodes.

Source code in conatus/actions/preloaded/browsing.py
@action(force_update_on="browser")
def add_nodes_to_set(
    browser: SimpleBrowser,
    node_ids: set[int],
    existing_set: Existing[set[DOMNode]] | None = None,
) -> Existing[set[DOMNode]]:
    """Add nodes to a (potentially pre-existing) set.

    Ids that aren't currently clickable on the page are silently skipped rather
    than raising.

    Args:
        browser: The browser to use.
        node_ids: The ids of the nodes to add.
        existing_set: The set to add the nodes to. If not provided, a new set
            will be created.

    Returns:
        (set[DOMNode]): The set of nodes.
    """
    existing_set_value = existing_set or set[DOMNode]()
    clickable = browser.page.last_step.clickable_elements
    # Skip ids that aren't currently clickable rather than raising KeyError:
    # the model occasionally references a stale/out-of-range id, and dropping it
    # is far more useful to an agent loop than crashing the whole step.
    dropped = [node_id for node_id in node_ids if node_id not in clickable]
    if dropped:
        logger.debug("add_nodes_to_set: dropping non-clickable ids %s", dropped)
    return existing_set_value | {
        clickable[node_id] for node_id in node_ids if node_id in clickable
    }

conatus.actions.preloaded.browsing.browser_mousedown conatus-action

browser_mousedown(
    browser: SimpleBrowser,
    *,
    x: float | None = None,
    y: float | None = None,
    button: MouseButton = "left"
) -> None
This function is an Action

You can call browser_mousedown just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_mousedown has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Mouse down on an element at a given position.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

x

The x coordinate of the element to click.

TYPE: float | None DEFAULT: None

y

The y coordinate of the element to click.

TYPE: float | None DEFAULT: None

button

The button to click on. Defaults to "left".

TYPE: MouseButton DEFAULT: 'left'

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_mousedown(
    browser: SimpleBrowser,
    *,
    x: float | None = None,
    y: float | None = None,
    button: MouseButton = "left",
) -> None:
    """Mouse down on an element at a given position.

    Args:
        browser: The browser to use.
        x: The x coordinate of the element to click.
        y: The y coordinate of the element to click.
        button: The button to click on. Defaults to `"left"`.
    """
    _ = browser.mousedown(x, y, button)

conatus.actions.preloaded.browsing.browser_mouseup conatus-action

browser_mouseup(
    browser: SimpleBrowser,
    *,
    x: float | None = None,
    y: float | None = None,
    button: MouseButton = "left"
) -> None
This function is an Action

You can call browser_mouseup just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_mouseup has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Mouse up on an element at a given position.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

x

The x coordinate of the element to click.

TYPE: float | None DEFAULT: None

y

The y coordinate of the element to click.

TYPE: float | None DEFAULT: None

button

The button to click on. Defaults to "left".

TYPE: MouseButton DEFAULT: 'left'

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_mouseup(
    browser: SimpleBrowser,
    *,
    x: float | None = None,
    y: float | None = None,
    button: MouseButton = "left",
) -> None:
    """Mouse up on an element at a given position.

    Args:
        browser: The browser to use.
        x: The x coordinate of the element to click.
        y: The y coordinate of the element to click.
        button: The button to click on. Defaults to `"left"`.
    """
    _ = browser.mouseup(x, y, button)

conatus.actions.preloaded.browsing.browser_mouse_move conatus-action

browser_mouse_move(
    browser: SimpleBrowser, x: float, y: float
) -> None
This function is an Action

You can call browser_mouse_move just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_mouse_move has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Move the mouse to a given position.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

x

The x coordinate of the element to click.

TYPE: float

y

The y coordinate of the element to click.

TYPE: float

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_mouse_move(
    browser: SimpleBrowser,
    x: float,
    y: float,
) -> None:
    """Move the mouse to a given position.

    Args:
        browser: The browser to use.
        x: The x coordinate of the element to click.
        y: The y coordinate of the element to click.
    """
    _ = browser.mouse_move(x, y, wait_for_load=True)

conatus.actions.preloaded.browsing.browser_drag conatus-action

browser_drag(
    browser: SimpleBrowser, path: list[tuple[float, float]]
) -> None
This function is an Action

You can call browser_drag just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_drag has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Drag the mouse.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

path

The path to drag the mouse to.

TYPE: list[tuple[float, float]]

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_drag(
    browser: SimpleBrowser,
    path: list[tuple[float, float]],
) -> None:
    """Drag the mouse.

    Args:
        browser: The browser to use.
        path: The path to drag the mouse to.
    """
    _ = browser.drag(path, wait_for_load=True)

conatus.actions.preloaded.browsing.browser_scroll conatus-action

browser_scroll(
    browser: SimpleBrowser,
    direction: ScrollDirection,
    *,
    magnitude_px: int | None = None,
    magnitude_relative: float | None = None
) -> None
This function is an Action

You can call browser_scroll just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_scroll has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Scroll the browser.

Unless you know what you are doing, you should use the magnitude_relative argument.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

direction

The direction to scroll.

TYPE: ScrollDirection

magnitude_px

The magnitude to scroll.

TYPE: int | None DEFAULT: None

magnitude_relative

The magnitude to scroll relative to the current viewport size.

TYPE: float | None DEFAULT: None

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_scroll(
    browser: SimpleBrowser,
    direction: ScrollDirection,
    *,
    magnitude_px: int | None = None,
    magnitude_relative: float | None = None,
) -> None:
    """Scroll the browser.

    Unless you know what you are doing, you should use the `magnitude_relative`
    argument.

    Args:
        browser: The browser to use.
        direction: The direction to scroll.
        magnitude_px: The magnitude to scroll.
        magnitude_relative: The magnitude to scroll relative to the current
            viewport size.
    """
    _ = browser.scroll(
        direction,
        magnitude_px,
        magnitude_relative,
        wait_for_load=True,
    )

conatus.actions.preloaded.browsing.browser_scroll_precise conatus-action

browser_scroll_precise(
    browser: SimpleBrowser,
    delta_x: float,
    delta_y: float,
    *,
    start_x: float | None = None,
    start_y: float | None = None
) -> None
This function is an Action

You can call browser_scroll_precise just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_scroll_precise has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Scroll the browser precisely.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

delta_x

The x coordinate of the scroll distance.

TYPE: float

delta_y

The y coordinate of the scroll distance.

TYPE: float

start_x

The x coordinate to start scrolling from.

TYPE: float | None DEFAULT: None

start_y

The y coordinate to start scrolling from.

TYPE: float | None DEFAULT: None

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_scroll_precise(
    browser: SimpleBrowser,
    delta_x: float,
    delta_y: float,
    *,
    start_x: float | None = None,
    start_y: float | None = None,
) -> None:
    """Scroll the browser precisely.

    Args:
        browser: The browser to use.
        delta_x: The x coordinate of the scroll distance.
        delta_y: The y coordinate of the scroll distance.
        start_x: The x coordinate to start scrolling from.
        start_y: The y coordinate to start scrolling from.
    """
    _ = browser.scroll_precise(
        delta_x,
        delta_y,
        start_x=start_x,
        start_y=start_y,
        wait_for_load=True,
    )

conatus.actions.preloaded.browsing.browser_keypress conatus-action

browser_keypress(
    browser: SimpleBrowser,
    keys: list[str],
    *,
    duration: float = 0
) -> None
This function is an Action

You can call browser_keypress just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_keypress has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Press keys into the page.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

keys

The keys to press.

TYPE: list[str]

duration

The duration to hold the key.

TYPE: float DEFAULT: 0

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_keypress(
    browser: SimpleBrowser,
    keys: list[str],
    *,
    duration: float = 0,
) -> None:
    """Press keys into the page.

    Args:
        browser: The browser to use.
        keys: The keys to press.
        duration: The duration to hold the key.
    """
    _ = browser.keypress(keys, duration, wait_for_load=True)

conatus.actions.preloaded.browsing.browser_type conatus-action

browser_type(browser: SimpleBrowser, text: str) -> None
This function is an Action

You can call browser_type just like a regular function, but note that it is actually a Action object.

This means that:

  • browser_type has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Type text into the page.

PARAMETER DESCRIPTION
browser

The browser to use.

TYPE: SimpleBrowser

text

The text to type.

TYPE: str

Source code in conatus/actions/preloaded/browsing.py
@action(hide_if_computer_use_mode=True, force_update_on="browser")
def browser_type(
    browser: SimpleBrowser,
    text: str,
) -> None:
    """Type text into the page.

    Args:
        browser: The browser to use.
        text: The text to type.
    """
    _ = browser.type(text, wait_for_load=True)

conatus.actions.preloaded.browsing.inspect_at conatus-action

inspect_at(
    browser: SimpleBrowser, x: float, y: float
) -> str
This function is an Action

You can call inspect_at just like a regular function, but note that it is actually a Action object.

This means that:

  • inspect_at has additional properties and methods that you can use (see the Action documentation for more information);
  • but it also means that operations like issubclass and isinstance will not work as expected.

Describe the DOM element at screen point (x, y).

Like a dev-tools inspector: uses the page's already-detected nodes (no extra CDP round-trip) to find the smallest (most specific) node whose bounding box covers the point. Handy for turning "the thing at this spot on the screenshot" into a concrete element.

PARAMETER DESCRIPTION
browser

The browser whose current page to inspect.

TYPE: SimpleBrowser

x

Horizontal screen coordinate (pixels).

TYPE: float

y

Vertical screen coordinate (pixels).

TYPE: float

RETURNS DESCRIPTION
str

A one-line description (tag, visible text, identifying attributes) of the element at that point, or a notice if none covers it.

Source code in conatus/actions/preloaded/browsing.py
@action
def inspect_at(browser: SimpleBrowser, x: float, y: float) -> str:
    """Describe the DOM element at screen point (x, y).

    Like a dev-tools inspector: uses the page's already-detected nodes (no extra
    CDP round-trip) to find the smallest (most specific) node whose bounding box
    covers the point. Handy for turning "the thing at this spot on the
    screenshot" into a concrete element.

    Args:
        browser: The browser whose current page to inspect.
        x: Horizontal screen coordinate (pixels).
        y: Vertical screen coordinate (pixels).

    Returns:
        (str): A one-line description (tag, visible text, identifying
            attributes) of the element at that point, or a notice if none
            covers it.
    """
    # TODO(lemeb): When elements overlap, this returns only the smallest node.
    # An improvement would be to return every node covering the point.
    # CTUS-79
    best: tuple[float, DOMNode] | None = None
    for node in browser.page.last_step.nodes:
        if node.bounds is None:
            continue
        bx, by, bw, bh = node.bounds
        area = bw * bh
        if area <= 0 or not (bx <= x <= bx + bw and by <= y <= by + bh):
            continue
        if best is None or area < best[0]:
            best = (area, node)
    if best is None:
        return f"(no DOM node found at ({x:.0f}, {y:.0f}))"
    node = best[1]
    text = " ".join(node.inner_text.split())[:80]
    dumped: dict[str, object] = node.identifying_attributes.model_dump(
        exclude_none=True
    )
    attrs = " ".join(f"{k}={v}" for k, v in dumped.items() if v)[:110]
    suffix = f" · {attrs}" if attrs else ""
    return f"<{node.node_name}> at ({x:.0f},{y:.0f}): text={text!r}{suffix}"