code-puppy 0.0.177__py3-none-any.whl → 0.0.179__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_puppy/agents/agent_golang_reviewer.py +61 -0
- code_puppy/agents/base_agent.py +8 -11
- code_puppy/main.py +2 -0
- code_puppy/tui/app.py +2 -0
- {code_puppy-0.0.177.dist-info → code_puppy-0.0.179.dist-info}/METADATA +1 -1
- {code_puppy-0.0.177.dist-info → code_puppy-0.0.179.dist-info}/RECORD +10 -16
- code_puppy/tools/browser_control.py +0 -293
- code_puppy/tools/browser_interactions.py +0 -552
- code_puppy/tools/browser_locators.py +0 -642
- code_puppy/tools/browser_navigation.py +0 -251
- code_puppy/tools/browser_screenshot.py +0 -278
- code_puppy/tools/browser_scripts.py +0 -472
- code_puppy/tools/browser_workflows.py +0 -223
- {code_puppy-0.0.177.data → code_puppy-0.0.179.data}/data/code_puppy/models.json +0 -0
- {code_puppy-0.0.177.dist-info → code_puppy-0.0.179.dist-info}/WHEEL +0 -0
- {code_puppy-0.0.177.dist-info → code_puppy-0.0.179.dist-info}/entry_points.txt +0 -0
- {code_puppy-0.0.177.dist-info → code_puppy-0.0.179.dist-info}/licenses/LICENSE +0 -0
@@ -1,642 +0,0 @@
|
|
1
|
-
"""Browser element discovery tools using semantic locators and XPath."""
|
2
|
-
|
3
|
-
from typing import Any, Dict, Optional
|
4
|
-
|
5
|
-
from pydantic_ai import RunContext
|
6
|
-
|
7
|
-
from code_puppy.messaging import emit_info
|
8
|
-
from code_puppy.tools.common import generate_group_id
|
9
|
-
|
10
|
-
from .camoufox_manager import get_camoufox_manager
|
11
|
-
|
12
|
-
|
13
|
-
async def find_by_role(
|
14
|
-
role: str,
|
15
|
-
name: Optional[str] = None,
|
16
|
-
exact: bool = False,
|
17
|
-
timeout: int = 10000,
|
18
|
-
) -> Dict[str, Any]:
|
19
|
-
"""Find elements by ARIA role."""
|
20
|
-
group_id = generate_group_id("browser_find_by_role", f"{role}_{name or 'any'}")
|
21
|
-
emit_info(
|
22
|
-
f"[bold white on blue] BROWSER FIND BY ROLE [/bold white on blue] 🎨 role={role} name={name}",
|
23
|
-
message_group=group_id,
|
24
|
-
)
|
25
|
-
try:
|
26
|
-
browser_manager = get_camoufox_manager()
|
27
|
-
page = await browser_manager.get_current_page()
|
28
|
-
|
29
|
-
if not page:
|
30
|
-
return {"success": False, "error": "No active browser page available"}
|
31
|
-
|
32
|
-
# Build locator
|
33
|
-
locator = page.get_by_role(role, name=name, exact=exact)
|
34
|
-
|
35
|
-
# Wait for at least one element
|
36
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
37
|
-
|
38
|
-
# Count elements
|
39
|
-
count = await locator.count()
|
40
|
-
|
41
|
-
# Get element info
|
42
|
-
elements = []
|
43
|
-
for i in range(min(count, 10)): # Limit to first 10 elements
|
44
|
-
element = locator.nth(i)
|
45
|
-
if await element.is_visible():
|
46
|
-
text = await element.text_content()
|
47
|
-
elements.append({"index": i, "text": text, "visible": True})
|
48
|
-
|
49
|
-
emit_info(
|
50
|
-
f"[green]Found {count} elements with role '{role}'[/green]",
|
51
|
-
message_group=group_id,
|
52
|
-
)
|
53
|
-
|
54
|
-
return {
|
55
|
-
"success": True,
|
56
|
-
"role": role,
|
57
|
-
"name": name,
|
58
|
-
"count": count,
|
59
|
-
"elements": elements,
|
60
|
-
}
|
61
|
-
|
62
|
-
except Exception as e:
|
63
|
-
return {"success": False, "error": str(e), "role": role, "name": name}
|
64
|
-
|
65
|
-
|
66
|
-
async def find_by_text(
|
67
|
-
text: str,
|
68
|
-
exact: bool = False,
|
69
|
-
timeout: int = 10000,
|
70
|
-
) -> Dict[str, Any]:
|
71
|
-
"""Find elements containing specific text."""
|
72
|
-
group_id = generate_group_id("browser_find_by_text", text[:50])
|
73
|
-
emit_info(
|
74
|
-
f"[bold white on blue] BROWSER FIND BY TEXT [/bold white on blue] 🔍 text='{text}' exact={exact}",
|
75
|
-
message_group=group_id,
|
76
|
-
)
|
77
|
-
try:
|
78
|
-
browser_manager = get_camoufox_manager()
|
79
|
-
page = await browser_manager.get_current_page()
|
80
|
-
|
81
|
-
if not page:
|
82
|
-
return {"success": False, "error": "No active browser page available"}
|
83
|
-
|
84
|
-
locator = page.get_by_text(text, exact=exact)
|
85
|
-
|
86
|
-
# Wait for at least one element
|
87
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
88
|
-
|
89
|
-
count = await locator.count()
|
90
|
-
|
91
|
-
elements = []
|
92
|
-
for i in range(min(count, 10)):
|
93
|
-
element = locator.nth(i)
|
94
|
-
if await element.is_visible():
|
95
|
-
tag_name = await element.evaluate("el => el.tagName.toLowerCase()")
|
96
|
-
full_text = await element.text_content()
|
97
|
-
elements.append(
|
98
|
-
{"index": i, "tag": tag_name, "text": full_text, "visible": True}
|
99
|
-
)
|
100
|
-
|
101
|
-
emit_info(
|
102
|
-
f"[green]Found {count} elements containing text '{text}'[/green]",
|
103
|
-
message_group=group_id,
|
104
|
-
)
|
105
|
-
|
106
|
-
return {
|
107
|
-
"success": True,
|
108
|
-
"search_text": text,
|
109
|
-
"exact": exact,
|
110
|
-
"count": count,
|
111
|
-
"elements": elements,
|
112
|
-
}
|
113
|
-
|
114
|
-
except Exception as e:
|
115
|
-
return {"success": False, "error": str(e), "search_text": text}
|
116
|
-
|
117
|
-
|
118
|
-
async def find_by_label(
|
119
|
-
text: str,
|
120
|
-
exact: bool = False,
|
121
|
-
timeout: int = 10000,
|
122
|
-
) -> Dict[str, Any]:
|
123
|
-
"""Find form elements by their associated label text."""
|
124
|
-
group_id = generate_group_id("browser_find_by_label", text[:50])
|
125
|
-
emit_info(
|
126
|
-
f"[bold white on blue] BROWSER FIND BY LABEL [/bold white on blue] 🏷️ label='{text}' exact={exact}",
|
127
|
-
message_group=group_id,
|
128
|
-
)
|
129
|
-
try:
|
130
|
-
browser_manager = get_camoufox_manager()
|
131
|
-
page = await browser_manager.get_current_page()
|
132
|
-
|
133
|
-
if not page:
|
134
|
-
return {"success": False, "error": "No active browser page available"}
|
135
|
-
|
136
|
-
locator = page.get_by_label(text, exact=exact)
|
137
|
-
|
138
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
139
|
-
|
140
|
-
count = await locator.count()
|
141
|
-
|
142
|
-
elements = []
|
143
|
-
for i in range(min(count, 10)):
|
144
|
-
element = locator.nth(i)
|
145
|
-
if await element.is_visible():
|
146
|
-
tag_name = await element.evaluate("el => el.tagName.toLowerCase()")
|
147
|
-
input_type = await element.get_attribute("type")
|
148
|
-
value = (
|
149
|
-
await element.input_value()
|
150
|
-
if tag_name in ["input", "textarea"]
|
151
|
-
else None
|
152
|
-
)
|
153
|
-
|
154
|
-
elements.append(
|
155
|
-
{
|
156
|
-
"index": i,
|
157
|
-
"tag": tag_name,
|
158
|
-
"type": input_type,
|
159
|
-
"value": value,
|
160
|
-
"visible": True,
|
161
|
-
}
|
162
|
-
)
|
163
|
-
|
164
|
-
emit_info(
|
165
|
-
f"[green]Found {count} elements with label '{text}'[/green]",
|
166
|
-
message_group=group_id,
|
167
|
-
)
|
168
|
-
|
169
|
-
return {
|
170
|
-
"success": True,
|
171
|
-
"label_text": text,
|
172
|
-
"exact": exact,
|
173
|
-
"count": count,
|
174
|
-
"elements": elements,
|
175
|
-
}
|
176
|
-
|
177
|
-
except Exception as e:
|
178
|
-
return {"success": False, "error": str(e), "label_text": text}
|
179
|
-
|
180
|
-
|
181
|
-
async def find_by_placeholder(
|
182
|
-
text: str,
|
183
|
-
exact: bool = False,
|
184
|
-
timeout: int = 10000,
|
185
|
-
) -> Dict[str, Any]:
|
186
|
-
"""Find elements by placeholder text."""
|
187
|
-
group_id = generate_group_id("browser_find_by_placeholder", text[:50])
|
188
|
-
emit_info(
|
189
|
-
f"[bold white on blue] BROWSER FIND BY PLACEHOLDER [/bold white on blue] 📝 placeholder='{text}' exact={exact}",
|
190
|
-
message_group=group_id,
|
191
|
-
)
|
192
|
-
try:
|
193
|
-
browser_manager = get_camoufox_manager()
|
194
|
-
page = await browser_manager.get_current_page()
|
195
|
-
|
196
|
-
if not page:
|
197
|
-
return {"success": False, "error": "No active browser page available"}
|
198
|
-
|
199
|
-
locator = page.get_by_placeholder(text, exact=exact)
|
200
|
-
|
201
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
202
|
-
|
203
|
-
count = await locator.count()
|
204
|
-
|
205
|
-
elements = []
|
206
|
-
for i in range(min(count, 10)):
|
207
|
-
element = locator.nth(i)
|
208
|
-
if await element.is_visible():
|
209
|
-
tag_name = await element.evaluate("el => el.tagName.toLowerCase()")
|
210
|
-
placeholder = await element.get_attribute("placeholder")
|
211
|
-
value = await element.input_value()
|
212
|
-
|
213
|
-
elements.append(
|
214
|
-
{
|
215
|
-
"index": i,
|
216
|
-
"tag": tag_name,
|
217
|
-
"placeholder": placeholder,
|
218
|
-
"value": value,
|
219
|
-
"visible": True,
|
220
|
-
}
|
221
|
-
)
|
222
|
-
|
223
|
-
emit_info(
|
224
|
-
f"[green]Found {count} elements with placeholder '{text}'[/green]",
|
225
|
-
message_group=group_id,
|
226
|
-
)
|
227
|
-
|
228
|
-
return {
|
229
|
-
"success": True,
|
230
|
-
"placeholder_text": text,
|
231
|
-
"exact": exact,
|
232
|
-
"count": count,
|
233
|
-
"elements": elements,
|
234
|
-
}
|
235
|
-
|
236
|
-
except Exception as e:
|
237
|
-
return {"success": False, "error": str(e), "placeholder_text": text}
|
238
|
-
|
239
|
-
|
240
|
-
async def find_by_test_id(
|
241
|
-
test_id: str,
|
242
|
-
timeout: int = 10000,
|
243
|
-
) -> Dict[str, Any]:
|
244
|
-
"""Find elements by test ID attribute."""
|
245
|
-
group_id = generate_group_id("browser_find_by_test_id", test_id)
|
246
|
-
emit_info(
|
247
|
-
f"[bold white on blue] BROWSER FIND BY TEST ID [/bold white on blue] 🧪 test_id='{test_id}'",
|
248
|
-
message_group=group_id,
|
249
|
-
)
|
250
|
-
try:
|
251
|
-
browser_manager = get_camoufox_manager()
|
252
|
-
page = await browser_manager.get_current_page()
|
253
|
-
|
254
|
-
if not page:
|
255
|
-
return {"success": False, "error": "No active browser page available"}
|
256
|
-
|
257
|
-
locator = page.get_by_test_id(test_id)
|
258
|
-
|
259
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
260
|
-
|
261
|
-
count = await locator.count()
|
262
|
-
|
263
|
-
elements = []
|
264
|
-
for i in range(min(count, 10)):
|
265
|
-
element = locator.nth(i)
|
266
|
-
if await element.is_visible():
|
267
|
-
tag_name = await element.evaluate("el => el.tagName.toLowerCase()")
|
268
|
-
text = await element.text_content()
|
269
|
-
|
270
|
-
elements.append(
|
271
|
-
{
|
272
|
-
"index": i,
|
273
|
-
"tag": tag_name,
|
274
|
-
"text": text,
|
275
|
-
"test_id": test_id,
|
276
|
-
"visible": True,
|
277
|
-
}
|
278
|
-
)
|
279
|
-
|
280
|
-
emit_info(
|
281
|
-
f"[green]Found {count} elements with test-id '{test_id}'[/green]",
|
282
|
-
message_group=group_id,
|
283
|
-
)
|
284
|
-
|
285
|
-
return {
|
286
|
-
"success": True,
|
287
|
-
"test_id": test_id,
|
288
|
-
"count": count,
|
289
|
-
"elements": elements,
|
290
|
-
}
|
291
|
-
|
292
|
-
except Exception as e:
|
293
|
-
return {"success": False, "error": str(e), "test_id": test_id}
|
294
|
-
|
295
|
-
|
296
|
-
async def run_xpath_query(
|
297
|
-
xpath: str,
|
298
|
-
timeout: int = 10000,
|
299
|
-
) -> Dict[str, Any]:
|
300
|
-
"""Find elements using XPath selector."""
|
301
|
-
group_id = generate_group_id("browser_xpath_query", xpath[:100])
|
302
|
-
emit_info(
|
303
|
-
f"[bold white on blue] BROWSER XPATH QUERY [/bold white on blue] 🔍 xpath='{xpath}'",
|
304
|
-
message_group=group_id,
|
305
|
-
)
|
306
|
-
try:
|
307
|
-
browser_manager = get_camoufox_manager()
|
308
|
-
page = await browser_manager.get_current_page()
|
309
|
-
|
310
|
-
if not page:
|
311
|
-
return {"success": False, "error": "No active browser page available"}
|
312
|
-
|
313
|
-
# Use page.locator with xpath
|
314
|
-
locator = page.locator(f"xpath={xpath}")
|
315
|
-
|
316
|
-
# Wait for at least one element
|
317
|
-
await locator.first.wait_for(state="visible", timeout=timeout)
|
318
|
-
|
319
|
-
count = await locator.count()
|
320
|
-
|
321
|
-
elements = []
|
322
|
-
for i in range(min(count, 10)):
|
323
|
-
element = locator.nth(i)
|
324
|
-
if await element.is_visible():
|
325
|
-
tag_name = await element.evaluate("el => el.tagName.toLowerCase()")
|
326
|
-
text = await element.text_content()
|
327
|
-
class_name = await element.get_attribute("class")
|
328
|
-
element_id = await element.get_attribute("id")
|
329
|
-
|
330
|
-
elements.append(
|
331
|
-
{
|
332
|
-
"index": i,
|
333
|
-
"tag": tag_name,
|
334
|
-
"text": text[:100] if text else None, # Truncate long text
|
335
|
-
"class": class_name,
|
336
|
-
"id": element_id,
|
337
|
-
"visible": True,
|
338
|
-
}
|
339
|
-
)
|
340
|
-
|
341
|
-
emit_info(
|
342
|
-
f"[green]Found {count} elements with XPath '{xpath}'[/green]",
|
343
|
-
message_group=group_id,
|
344
|
-
)
|
345
|
-
|
346
|
-
return {"success": True, "xpath": xpath, "count": count, "elements": elements}
|
347
|
-
|
348
|
-
except Exception as e:
|
349
|
-
return {"success": False, "error": str(e), "xpath": xpath}
|
350
|
-
|
351
|
-
|
352
|
-
async def find_buttons(
|
353
|
-
text_filter: Optional[str] = None, timeout: int = 10000
|
354
|
-
) -> Dict[str, Any]:
|
355
|
-
"""Find all button elements on the page."""
|
356
|
-
group_id = generate_group_id("browser_find_buttons", text_filter or "all")
|
357
|
-
emit_info(
|
358
|
-
f"[bold white on blue] BROWSER FIND BUTTONS [/bold white on blue] 🔘 filter='{text_filter or 'none'}'",
|
359
|
-
message_group=group_id,
|
360
|
-
)
|
361
|
-
try:
|
362
|
-
browser_manager = get_camoufox_manager()
|
363
|
-
page = await browser_manager.get_current_page()
|
364
|
-
|
365
|
-
if not page:
|
366
|
-
return {"success": False, "error": "No active browser page available"}
|
367
|
-
|
368
|
-
# Find buttons by role
|
369
|
-
locator = page.get_by_role("button")
|
370
|
-
|
371
|
-
count = await locator.count()
|
372
|
-
|
373
|
-
buttons = []
|
374
|
-
for i in range(min(count, 20)): # Limit to 20 buttons
|
375
|
-
button = locator.nth(i)
|
376
|
-
if await button.is_visible():
|
377
|
-
text = await button.text_content()
|
378
|
-
if text_filter and text_filter.lower() not in text.lower():
|
379
|
-
continue
|
380
|
-
|
381
|
-
buttons.append({"index": i, "text": text, "visible": True})
|
382
|
-
|
383
|
-
filtered_count = len(buttons)
|
384
|
-
|
385
|
-
emit_info(
|
386
|
-
f"[green]Found {filtered_count} buttons"
|
387
|
-
+ (f" containing '{text_filter}'" if text_filter else "")
|
388
|
-
+ "[/green]",
|
389
|
-
message_group=group_id,
|
390
|
-
)
|
391
|
-
|
392
|
-
return {
|
393
|
-
"success": True,
|
394
|
-
"text_filter": text_filter,
|
395
|
-
"total_count": count,
|
396
|
-
"filtered_count": filtered_count,
|
397
|
-
"buttons": buttons,
|
398
|
-
}
|
399
|
-
|
400
|
-
except Exception as e:
|
401
|
-
return {"success": False, "error": str(e), "text_filter": text_filter}
|
402
|
-
|
403
|
-
|
404
|
-
async def find_links(
|
405
|
-
text_filter: Optional[str] = None, timeout: int = 10000
|
406
|
-
) -> Dict[str, Any]:
|
407
|
-
"""Find all link elements on the page."""
|
408
|
-
group_id = generate_group_id("browser_find_links", text_filter or "all")
|
409
|
-
emit_info(
|
410
|
-
f"[bold white on blue] BROWSER FIND LINKS [/bold white on blue] 🔗 filter='{text_filter or 'none'}'",
|
411
|
-
message_group=group_id,
|
412
|
-
)
|
413
|
-
try:
|
414
|
-
browser_manager = get_camoufox_manager()
|
415
|
-
page = await browser_manager.get_current_page()
|
416
|
-
|
417
|
-
if not page:
|
418
|
-
return {"success": False, "error": "No active browser page available"}
|
419
|
-
|
420
|
-
# Find links by role
|
421
|
-
locator = page.get_by_role("link")
|
422
|
-
|
423
|
-
count = await locator.count()
|
424
|
-
|
425
|
-
links = []
|
426
|
-
for i in range(min(count, 20)): # Limit to 20 links
|
427
|
-
link = locator.nth(i)
|
428
|
-
if await link.is_visible():
|
429
|
-
text = await link.text_content()
|
430
|
-
href = await link.get_attribute("href")
|
431
|
-
|
432
|
-
if text_filter and text_filter.lower() not in text.lower():
|
433
|
-
continue
|
434
|
-
|
435
|
-
links.append({"index": i, "text": text, "href": href, "visible": True})
|
436
|
-
|
437
|
-
filtered_count = len(links)
|
438
|
-
|
439
|
-
emit_info(
|
440
|
-
f"[green]Found {filtered_count} links"
|
441
|
-
+ (f" containing '{text_filter}'" if text_filter else "")
|
442
|
-
+ "[/green]",
|
443
|
-
message_group=group_id,
|
444
|
-
)
|
445
|
-
|
446
|
-
return {
|
447
|
-
"success": True,
|
448
|
-
"text_filter": text_filter,
|
449
|
-
"total_count": count,
|
450
|
-
"filtered_count": filtered_count,
|
451
|
-
"links": links,
|
452
|
-
}
|
453
|
-
|
454
|
-
except Exception as e:
|
455
|
-
return {"success": False, "error": str(e), "text_filter": text_filter}
|
456
|
-
|
457
|
-
|
458
|
-
# Tool registration functions
|
459
|
-
def register_find_by_role(agent):
|
460
|
-
"""Register the find by role tool."""
|
461
|
-
|
462
|
-
@agent.tool
|
463
|
-
async def browser_find_by_role(
|
464
|
-
context: RunContext,
|
465
|
-
role: str,
|
466
|
-
name: Optional[str] = None,
|
467
|
-
exact: bool = False,
|
468
|
-
timeout: int = 10000,
|
469
|
-
) -> Dict[str, Any]:
|
470
|
-
"""
|
471
|
-
Find elements by ARIA role (recommended for accessibility).
|
472
|
-
|
473
|
-
Args:
|
474
|
-
role: ARIA role (button, link, textbox, heading, etc.)
|
475
|
-
name: Optional accessible name to filter by
|
476
|
-
exact: Whether to match name exactly
|
477
|
-
timeout: Timeout in milliseconds
|
478
|
-
|
479
|
-
Returns:
|
480
|
-
Dict with found elements and their properties
|
481
|
-
"""
|
482
|
-
return await find_by_role(role, name, exact, timeout)
|
483
|
-
|
484
|
-
|
485
|
-
def register_find_by_text(agent):
|
486
|
-
"""Register the find by text tool."""
|
487
|
-
|
488
|
-
@agent.tool
|
489
|
-
async def browser_find_by_text(
|
490
|
-
context: RunContext,
|
491
|
-
text: str,
|
492
|
-
exact: bool = False,
|
493
|
-
timeout: int = 10000,
|
494
|
-
) -> Dict[str, Any]:
|
495
|
-
"""
|
496
|
-
Find elements containing specific text content.
|
497
|
-
|
498
|
-
Args:
|
499
|
-
text: Text to search for
|
500
|
-
exact: Whether to match text exactly
|
501
|
-
timeout: Timeout in milliseconds
|
502
|
-
|
503
|
-
Returns:
|
504
|
-
Dict with found elements and their properties
|
505
|
-
"""
|
506
|
-
return await find_by_text(text, exact, timeout)
|
507
|
-
|
508
|
-
|
509
|
-
def register_find_by_label(agent):
|
510
|
-
"""Register the find by label tool."""
|
511
|
-
|
512
|
-
@agent.tool
|
513
|
-
async def browser_find_by_label(
|
514
|
-
context: RunContext,
|
515
|
-
text: str,
|
516
|
-
exact: bool = False,
|
517
|
-
timeout: int = 10000,
|
518
|
-
) -> Dict[str, Any]:
|
519
|
-
"""
|
520
|
-
Find form elements by their associated label text.
|
521
|
-
|
522
|
-
Args:
|
523
|
-
text: Label text to search for
|
524
|
-
exact: Whether to match label exactly
|
525
|
-
timeout: Timeout in milliseconds
|
526
|
-
|
527
|
-
Returns:
|
528
|
-
Dict with found form elements and their properties
|
529
|
-
"""
|
530
|
-
return await find_by_label(text, exact, timeout)
|
531
|
-
|
532
|
-
|
533
|
-
def register_find_by_placeholder(agent):
|
534
|
-
"""Register the find by placeholder tool."""
|
535
|
-
|
536
|
-
@agent.tool
|
537
|
-
async def browser_find_by_placeholder(
|
538
|
-
context: RunContext,
|
539
|
-
text: str,
|
540
|
-
exact: bool = False,
|
541
|
-
timeout: int = 10000,
|
542
|
-
) -> Dict[str, Any]:
|
543
|
-
"""
|
544
|
-
Find elements by placeholder text.
|
545
|
-
|
546
|
-
Args:
|
547
|
-
text: Placeholder text to search for
|
548
|
-
exact: Whether to match placeholder exactly
|
549
|
-
timeout: Timeout in milliseconds
|
550
|
-
|
551
|
-
Returns:
|
552
|
-
Dict with found elements and their properties
|
553
|
-
"""
|
554
|
-
return await find_by_placeholder(text, exact, timeout)
|
555
|
-
|
556
|
-
|
557
|
-
def register_find_by_test_id(agent):
|
558
|
-
"""Register the find by test ID tool."""
|
559
|
-
|
560
|
-
@agent.tool
|
561
|
-
async def browser_find_by_test_id(
|
562
|
-
context: RunContext,
|
563
|
-
test_id: str,
|
564
|
-
timeout: int = 10000,
|
565
|
-
) -> Dict[str, Any]:
|
566
|
-
"""
|
567
|
-
Find elements by test ID attribute (data-testid).
|
568
|
-
|
569
|
-
Args:
|
570
|
-
test_id: Test ID to search for
|
571
|
-
timeout: Timeout in milliseconds
|
572
|
-
|
573
|
-
Returns:
|
574
|
-
Dict with found elements and their properties
|
575
|
-
"""
|
576
|
-
return await find_by_test_id(test_id, timeout)
|
577
|
-
|
578
|
-
|
579
|
-
def register_run_xpath_query(agent):
|
580
|
-
"""Register the XPath query tool."""
|
581
|
-
|
582
|
-
@agent.tool
|
583
|
-
async def browser_xpath_query(
|
584
|
-
context: RunContext,
|
585
|
-
xpath: str,
|
586
|
-
timeout: int = 10000,
|
587
|
-
) -> Dict[str, Any]:
|
588
|
-
"""
|
589
|
-
Find elements using XPath selector (fallback when semantic locators fail).
|
590
|
-
|
591
|
-
Args:
|
592
|
-
xpath: XPath expression
|
593
|
-
timeout: Timeout in milliseconds
|
594
|
-
|
595
|
-
Returns:
|
596
|
-
Dict with found elements and their properties
|
597
|
-
"""
|
598
|
-
return await run_xpath_query(xpath, timeout)
|
599
|
-
|
600
|
-
|
601
|
-
def register_find_buttons(agent):
|
602
|
-
"""Register the find buttons tool."""
|
603
|
-
|
604
|
-
@agent.tool
|
605
|
-
async def browser_find_buttons(
|
606
|
-
context: RunContext,
|
607
|
-
text_filter: Optional[str] = None,
|
608
|
-
timeout: int = 10000,
|
609
|
-
) -> Dict[str, Any]:
|
610
|
-
"""
|
611
|
-
Find all button elements on the page.
|
612
|
-
|
613
|
-
Args:
|
614
|
-
text_filter: Optional text to filter buttons by
|
615
|
-
timeout: Timeout in milliseconds
|
616
|
-
|
617
|
-
Returns:
|
618
|
-
Dict with found buttons and their properties
|
619
|
-
"""
|
620
|
-
return await find_buttons(text_filter, timeout)
|
621
|
-
|
622
|
-
|
623
|
-
def register_find_links(agent):
|
624
|
-
"""Register the find links tool."""
|
625
|
-
|
626
|
-
@agent.tool
|
627
|
-
async def browser_find_links(
|
628
|
-
context: RunContext,
|
629
|
-
text_filter: Optional[str] = None,
|
630
|
-
timeout: int = 10000,
|
631
|
-
) -> Dict[str, Any]:
|
632
|
-
"""
|
633
|
-
Find all link elements on the page.
|
634
|
-
|
635
|
-
Args:
|
636
|
-
text_filter: Optional text to filter links by
|
637
|
-
timeout: Timeout in milliseconds
|
638
|
-
|
639
|
-
Returns:
|
640
|
-
Dict with found links and their properties
|
641
|
-
"""
|
642
|
-
return await find_links(text_filter, timeout)
|