From a6d1dac2d45e31771c710e1007aeba1bd426f91a Mon Sep 17 00:00:00 2001 From: Ishir Garg Date: Thu, 30 Apr 2026 16:02:57 -0700 Subject: [PATCH] Impl --- .../src/narada_core/actions/models.py | 21 ++++++++++++++++ packages/narada/src/narada/window.py | 24 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/narada-core/src/narada_core/actions/models.py b/packages/narada-core/src/narada_core/actions/models.py index 0c456ef..7ec6161 100644 --- a/packages/narada-core/src/narada_core/actions/models.py +++ b/packages/narada-core/src/narada_core/actions/models.py @@ -427,6 +427,26 @@ class AgenticSelectorResponse(BaseModel): value: str | None +class WaitForElementRequest(BaseModel): + name: Literal["wait_for_element"] = "wait_for_element" + selectors: AgenticSelectors + state: Literal["visible", "hidden"] + timeout: int # milliseconds + + @override + def model_dump(self) -> dict[str, Any]: + return { + "name": self.name, + "selectors": _dump_agentic_selectors(self.selectors), + "state": self.state, + "timeout": self.timeout, + } + + +class WaitForElementResponse(BaseModel): + found: bool + + class Viewport(TypedDict): width: int height: int @@ -612,6 +632,7 @@ class UserApprovalResponse(BaseModel): | AgenticMouseActionRequest | CloseWindowRequest | GoToUrlRequest + | WaitForElementRequest | PrintMessageRequest | ReadGoogleSheetRequest | WriteGoogleSheetRequest diff --git a/packages/narada/src/narada/window.py b/packages/narada/src/narada/window.py index 29c359b..e9fae72 100644 --- a/packages/narada/src/narada/window.py +++ b/packages/narada/src/narada/window.py @@ -7,7 +7,7 @@ from http import HTTPStatus from io import IOBase from pathlib import Path -from typing import IO, Any, Mapping, TypeGuard, TypeVar, overload, override +from typing import IO, Any, Literal, Mapping, TypeGuard, TypeVar, overload, override import aiohttp from narada_core.actions.models import ( @@ -40,6 +40,8 @@ RecordedClick, UserApprovalRequest, UserApprovalResponse, + WaitForElementRequest, + WaitForElementResponse, WriteGoogleSheetRequest, parse_action_trace, ) @@ -532,6 +534,26 @@ async def go_to_url( GoToUrlRequest(url=url, new_tab=new_tab), timeout=timeout ) + async def wait_for_element( + self, + *, + selectors: AgenticSelectors, + state: Literal["visible", "hidden"], + timeout: int, + ) -> bool: + """Waits for an element matching the given selectors to reach the specified state. + + Returns True if the element was found, False if no selector matched before timeout. + """ + result = await self._run_extension_action( + WaitForElementRequest(selectors=selectors, state=state, timeout=timeout), + WaitForElementResponse, + timeout=timeout // 1000 + 30, + ) + if result is None: + return False + return result.found + async def get_url(self, *, timeout: int | None = None) -> GetUrlResponse: """Gets the URL of the current active page.""" return await self._run_extension_action(