diff --git a/packages/narada-core/src/narada_core/actions/models.py b/packages/narada-core/src/narada_core/actions/models.py index 358efa5..8961234 100644 --- a/packages/narada-core/src/narada_core/actions/models.py +++ b/packages/narada-core/src/narada_core/actions/models.py @@ -192,6 +192,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 @@ -396,6 +416,7 @@ class UserApprovalResponse(BaseModel): | AgenticMouseActionRequest | CloseWindowRequest | GoToUrlRequest + | WaitForElementRequest | PrintMessageRequest | ReadGoogleSheetRequest | ReadExcelSheetRequest diff --git a/packages/narada/src/narada/window.py b/packages/narada/src/narada/window.py index dff0332..c36694b 100644 --- a/packages/narada/src/narada/window.py +++ b/packages/narada/src/narada/window.py @@ -53,6 +53,8 @@ RecordedClick, UserApprovalRequest, UserApprovalResponse, + WaitForElementRequest, + WaitForElementResponse, WriteExcelSheetRequest, WriteGoogleSheetRequest, ) @@ -690,6 +692,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(