Skip to content

Commit 5657462

Browse files
Merge pull request #84 from askui/feat/extend-typing-with-locator
feat(agent): add support for locator in `type()`
2 parents c532431 + b73cb44 commit 5657462

File tree

1 file changed

+38
-8
lines changed

1 file changed

+38
-8
lines changed

src/askui/agent.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,18 @@ def click(
167167
msg += f" {repeat}x times"
168168
if locator is not None:
169169
msg += f" on {locator}"
170+
logger.debug("VisionAgent received instruction to %s", msg)
170171
self._reporter.add_message("User", msg)
172+
self._click(locator, button, repeat, model)
173+
174+
def _click(
175+
self,
176+
locator: Optional[str | Locator],
177+
button: Literal["left", "middle", "right"],
178+
repeat: int,
179+
model: ModelComposition | str | None,
180+
) -> None:
171181
if locator is not None:
172-
logger.debug("VisionAgent received instruction to click on %s", locator)
173182
self._mouse_move(locator, model)
174183
self.tools.os.click(button, repeat)
175184

@@ -294,30 +303,51 @@ def mouse_scroll(
294303
self._reporter.add_message("User", f'mouse_scroll: "{x}", "{y}"')
295304
self.tools.os.mouse_scroll(x, y)
296305

297-
@telemetry.record_call(exclude={"text"})
298-
@validate_call
306+
@telemetry.record_call(exclude={"text", "locator"})
307+
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
299308
def type(
300309
self,
301310
text: Annotated[str, Field(min_length=1)],
311+
locator: str | Locator | None = None,
312+
model: ModelComposition | str | None = None,
313+
clear: bool = True,
302314
) -> None:
303315
"""
304316
Types the specified text as if it were entered on a keyboard.
305317
318+
If `locator` is provided, it will first click on the element to give it focus before typing.
319+
If `clear` is `True` (default), it will triple click on the element to select the current text (in multi-line inputs like textareas the current line or paragraph) before typing.
320+
321+
**IMPORTANT:** `clear` only works if a `locator` is provided.
322+
306323
Args:
307324
text (str): The text to be typed. Must be at least `1` character long.
325+
locator (str | Locator | None, optional): The identifier or description of the element (e.g., input field) to type into. If `None`, types at the current focus.
326+
model (ModelComposition | str | None, optional): The composition or name of the model(s) to be used for locating the element, i.e., input field, to type into using the `locator`.
327+
clear (bool, optional): Whether to triple click on the element to give it focus and select the current text before typing. Defaults to `True`.
308328
309329
Example:
310330
```python
311331
from askui import VisionAgent
312332
313333
with VisionAgent() as agent:
314-
agent.type("Hello, world!") # Types "Hello, world!"
315-
agent.type("user@example.com") # Types an email address
316-
agent.type("password123") # Types a password
334+
agent.type("Hello, world!") # Types "Hello, world!" at current focus
335+
agent.type("user@example.com", locator="Email") # Clicks on "Email" input, then types
336+
agent.type("password123", locator="Password field", model="custom_model") # Uses specific model
337+
agent.type("Hello, world!", locator="Textarea", clear=False) # Types "Hello, world!" into textarea without clearing
317338
```
318339
"""
319-
self._reporter.add_message("User", f'type: "{text}"')
320-
logger.debug("VisionAgent received instruction to type '%s'", text)
340+
msg = f'type "{text}"'
341+
if locator is not None:
342+
msg += f" into {locator}"
343+
if clear:
344+
repeat = 3
345+
msg += " clearing the current content (line/paragraph) of input field"
346+
else:
347+
repeat = 1
348+
self._click(locator=locator, button="left", repeat=repeat, model=model)
349+
logger.debug("VisionAgent received instruction to %s", msg)
350+
self._reporter.add_message("User", msg)
321351
self.tools.os.type(text)
322352

323353
@overload

0 commit comments

Comments
 (0)