donobu 2.14.0 → 2.15.0

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.
Files changed (69) hide show
  1. package/dist/assets/donobu-virtual-mouse.svg +11 -0
  2. package/dist/assets/donobu.css +62 -0
  3. package/dist/assets/generated/parameter-schemas.json +139 -240
  4. package/dist/assets/generated/version +1 -1
  5. package/dist/assets/smart-selector-generator.js +61 -3
  6. package/dist/esm/assets/donobu-virtual-mouse.svg +11 -0
  7. package/dist/esm/assets/donobu.css +62 -0
  8. package/dist/esm/assets/generated/parameter-schemas.json +139 -240
  9. package/dist/esm/assets/generated/version +1 -1
  10. package/dist/esm/assets/smart-selector-generator.js +61 -3
  11. package/dist/esm/managers/DonobuFlow.d.ts.map +1 -1
  12. package/dist/esm/managers/DonobuFlow.js +13 -17
  13. package/dist/esm/managers/DonobuFlow.js.map +1 -1
  14. package/dist/esm/managers/DonobuFlowsManager.d.ts.map +1 -1
  15. package/dist/esm/managers/DonobuFlowsManager.js +77 -74
  16. package/dist/esm/managers/DonobuFlowsManager.js.map +1 -1
  17. package/dist/esm/managers/InteractionVisualizer.d.ts +10 -2
  18. package/dist/esm/managers/InteractionVisualizer.d.ts.map +1 -1
  19. package/dist/esm/managers/InteractionVisualizer.js +26 -38
  20. package/dist/esm/managers/InteractionVisualizer.js.map +1 -1
  21. package/dist/esm/playwrightTestExtensions.d.ts.map +1 -1
  22. package/dist/esm/playwrightTestExtensions.js +1 -12
  23. package/dist/esm/playwrightTestExtensions.js.map +1 -1
  24. package/dist/esm/tools/ClickTool.d.ts +1 -1
  25. package/dist/esm/tools/ClickTool.d.ts.map +1 -1
  26. package/dist/esm/tools/ClickTool.js +8 -5
  27. package/dist/esm/tools/ClickTool.js.map +1 -1
  28. package/dist/esm/tools/ReplayableInteraction.d.ts +10 -1
  29. package/dist/esm/tools/ReplayableInteraction.d.ts.map +1 -1
  30. package/dist/esm/tools/ReplayableInteraction.js +96 -33
  31. package/dist/esm/tools/ReplayableInteraction.js.map +1 -1
  32. package/dist/esm/utils/Logger.d.ts +2 -0
  33. package/dist/esm/utils/Logger.d.ts.map +1 -1
  34. package/dist/esm/utils/Logger.js +23 -14
  35. package/dist/esm/utils/Logger.js.map +1 -1
  36. package/dist/esm/utils/PlaywrightUtils.d.ts +8 -20
  37. package/dist/esm/utils/PlaywrightUtils.d.ts.map +1 -1
  38. package/dist/esm/utils/PlaywrightUtils.js +51 -168
  39. package/dist/esm/utils/PlaywrightUtils.js.map +1 -1
  40. package/dist/managers/DonobuFlow.d.ts.map +1 -1
  41. package/dist/managers/DonobuFlow.js +13 -17
  42. package/dist/managers/DonobuFlow.js.map +1 -1
  43. package/dist/managers/DonobuFlowsManager.d.ts.map +1 -1
  44. package/dist/managers/DonobuFlowsManager.js +77 -74
  45. package/dist/managers/DonobuFlowsManager.js.map +1 -1
  46. package/dist/managers/InteractionVisualizer.d.ts +10 -2
  47. package/dist/managers/InteractionVisualizer.d.ts.map +1 -1
  48. package/dist/managers/InteractionVisualizer.js +26 -38
  49. package/dist/managers/InteractionVisualizer.js.map +1 -1
  50. package/dist/playwrightTestExtensions.d.ts.map +1 -1
  51. package/dist/playwrightTestExtensions.js +1 -12
  52. package/dist/playwrightTestExtensions.js.map +1 -1
  53. package/dist/tools/ClickTool.d.ts +1 -1
  54. package/dist/tools/ClickTool.d.ts.map +1 -1
  55. package/dist/tools/ClickTool.js +8 -5
  56. package/dist/tools/ClickTool.js.map +1 -1
  57. package/dist/tools/ReplayableInteraction.d.ts +10 -1
  58. package/dist/tools/ReplayableInteraction.d.ts.map +1 -1
  59. package/dist/tools/ReplayableInteraction.js +96 -33
  60. package/dist/tools/ReplayableInteraction.js.map +1 -1
  61. package/dist/utils/Logger.d.ts +2 -0
  62. package/dist/utils/Logger.d.ts.map +1 -1
  63. package/dist/utils/Logger.js +23 -14
  64. package/dist/utils/Logger.js.map +1 -1
  65. package/dist/utils/PlaywrightUtils.d.ts +8 -20
  66. package/dist/utils/PlaywrightUtils.d.ts.map +1 -1
  67. package/dist/utils/PlaywrightUtils.js +51 -168
  68. package/dist/utils/PlaywrightUtils.js.map +1 -1
  69. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg"
2
+ width="32"
3
+ height="32"
4
+ viewBox="0 0 24 24"
5
+ fill="oklch(13.09% 0.005 165.18)"
6
+ stroke="oklch(83.04% 0.1698 83.99)"
7
+ stroke-width="2"
8
+ stroke-linecap="round"
9
+ stroke-linejoin="round">
10
+ <path d="M4.037 4.688a.495.495 0 0 1 .651-.651l16 6.5a.5.5 0 0 1-.063.947l-6.124 1.58a2 2 0 0 0-1.438 1.435l-1.579 6.126a.5.5 0 0 1-.947.063z" />
11
+ </svg>
@@ -0,0 +1,62 @@
1
+ .donobu-message {
2
+ z-index: 2147483647;
3
+ background-color: black;
4
+ color: white;
5
+ padding: 8px;
6
+ border-radius: 5px;
7
+ font-size: 12px;
8
+ font-family:
9
+ 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
10
+ display: block;
11
+ max-width: 300px;
12
+ white-space: pre-wrap;
13
+ box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.2);
14
+ position: absolute;
15
+ }
16
+ .donobu-virtual-mouse {
17
+ width: 24px;
18
+ height: 24px;
19
+ background-image: url('/donobu-virtual-mouse.svg');
20
+ background-repeat: no-repeat;
21
+ background-size: contain;
22
+ position: absolute;
23
+ z-index: 2147483646;
24
+ transition-property: left, top;
25
+ transition-timing-function: ease-in-out;
26
+ filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 0.5));
27
+ }
28
+ .donobu-virtual-mouse:hover {
29
+ transform: scale(1.1);
30
+ }
31
+ /* Ripple Effect */
32
+ .donobu-virtual-mouse::after {
33
+ content: '';
34
+ position: absolute;
35
+ left: 50%;
36
+ top: 50%;
37
+ width: 24px;
38
+ height: 24px;
39
+ background: oklch(83.04% 0.1698 83.99); /* Donobu Yellow */
40
+ opacity: 0;
41
+ border-radius: 50%;
42
+ transform: translate(-50%, -50%) scale(0);
43
+ filter: blur(4px);
44
+ pointer-events: none;
45
+ }
46
+ .donobu-virtual-mouse.rippling::after {
47
+ animation: ripple-pop 0.6s ease-out;
48
+ }
49
+ @keyframes ripple-pop {
50
+ 0% {
51
+ transform: translate(-50%, -50%) scale(0.5);
52
+ opacity: 0.3;
53
+ }
54
+ 40% {
55
+ transform: translate(-50%, -50%) scale(1);
56
+ opacity: 0.5;
57
+ }
58
+ 100% {
59
+ transform: translate(-50%, -50%) scale(2);
60
+ opacity: 0;
61
+ }
62
+ }
@@ -150,32 +150,87 @@
150
150
  "additionalProperties": false,
151
151
  "required": ["annotation", "rationale", "whyThisAnnotation"]
152
152
  },
153
- "HandleBrowserDialogToolCoreParameters": {
154
- "description": "The parameters for handling browser dialogs",
153
+ "InputTextToolCoreParameters": {
155
154
  "type": "object",
156
155
  "properties": {
157
156
  "text": {
158
- "description": "If this is a \"confirm\" dialog, a string of \"true\" will accept the dialog and a string of \"false\" will dismiss it.\nHowever, if this is a \"prompt\" dialog, any non-null string will accept it, and a null value will dismiss it.",
159
- "type": ["string", "null"]
157
+ "description": "The text to input.",
158
+ "type": "string"
159
+ },
160
+ "finalizeWithSubmit": {
161
+ "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
162
+ "type": "boolean"
160
163
  }
161
164
  },
162
165
  "additionalProperties": false,
163
- "required": ["text"]
166
+ "required": ["finalizeWithSubmit", "text"]
164
167
  },
165
- "HandleBrowserDialogToolGptParameters": {
168
+ "SelectorBasedInputTextToolParameters": {
166
169
  "type": "object",
167
170
  "properties": {
171
+ "selector": {
172
+ "description": "A query structure used to resolve specific a HTML element in a webpage.",
173
+ "type": "object",
174
+ "properties": {
175
+ "element": {
176
+ "description": "An prioritized list of element selectors to use to attempt to resolve the\ndesired element, going from most specific to least specific. The first\nelement selector that is successfully used, wins, and the rest are ignored.",
177
+ "type": "array",
178
+ "items": {
179
+ "type": "string"
180
+ }
181
+ },
182
+ "frame": {
183
+ "description": "A selector for the corresponding frame of the element to select.\nIf null, this means the primary frame of the page is used.",
184
+ "type": "string"
185
+ }
186
+ },
187
+ "additionalProperties": false,
188
+ "required": ["element", "frame"]
189
+ },
190
+ "text": {
191
+ "description": "The text to input.",
192
+ "type": "string"
193
+ },
194
+ "finalizeWithSubmit": {
195
+ "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
196
+ "type": "boolean"
197
+ }
198
+ },
199
+ "additionalProperties": false,
200
+ "required": ["finalizeWithSubmit", "selector", "text"]
201
+ },
202
+ "AnnotationBasedInputTextToolParameters": {
203
+ "type": "object",
204
+ "properties": {
205
+ "whyThisAnnotation": {
206
+ "description": "The reason why this particular numbered annotation was chosen.",
207
+ "type": "string"
208
+ },
209
+ "annotation": {
210
+ "description": "The numbered annotation of the element to click.",
211
+ "type": "string"
212
+ },
168
213
  "rationale": {
169
214
  "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
170
215
  "type": "string"
171
216
  },
172
217
  "text": {
173
- "description": "If this is a \"confirm\" dialog, a string of \"true\" will accept the dialog and a string of \"false\" will dismiss it.\nHowever, if this is a \"prompt\" dialog, any non-null string will accept it, and a null value will dismiss it.",
174
- "type": ["string", "null"]
218
+ "description": "The text to input.",
219
+ "type": "string"
220
+ },
221
+ "finalizeWithSubmit": {
222
+ "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
223
+ "type": "boolean"
175
224
  }
176
225
  },
177
226
  "additionalProperties": false,
178
- "required": ["rationale", "text"]
227
+ "required": [
228
+ "annotation",
229
+ "finalizeWithSubmit",
230
+ "rationale",
231
+ "text",
232
+ "whyThisAnnotation"
233
+ ]
179
234
  },
180
235
  "InputRandomizedEmailAddressToolCoreParameters": {
181
236
  "type": "object",
@@ -259,55 +314,6 @@
259
314
  "whyThisAnnotation"
260
315
  ]
261
316
  },
262
- "MarkObjectiveCompleteToolCoreParameters": {
263
- "description": "Parameters for marking an objective as complete",
264
- "type": "object",
265
- "additionalProperties": false,
266
- "required": [],
267
- "properties": {}
268
- },
269
- "MarkObjectiveCompleteToolGptParameters": {
270
- "description": "Parameters for marking an objective as complete",
271
- "type": "object",
272
- "properties": {
273
- "details": {
274
- "description": "Relevant details for the completed objective.",
275
- "type": "string"
276
- },
277
- "rationale": {
278
- "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
279
- "type": "string"
280
- }
281
- },
282
- "additionalProperties": false,
283
- "required": ["details", "rationale"]
284
- },
285
- "GoToWebpageToolCoreParameters": {
286
- "type": "object",
287
- "properties": {
288
- "url": {
289
- "description": "The URL to navigate to. Must use the http or https (example is https://google.com).",
290
- "type": "string"
291
- }
292
- },
293
- "additionalProperties": false,
294
- "required": ["url"]
295
- },
296
- "GoToWebpageToolGptParameters": {
297
- "type": "object",
298
- "properties": {
299
- "rationale": {
300
- "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
301
- "type": "string"
302
- },
303
- "url": {
304
- "description": "The URL to navigate to. Must use the http or https (example is https://google.com).",
305
- "type": "string"
306
- }
307
- },
308
- "additionalProperties": false,
309
- "required": ["rationale", "url"]
310
- },
311
317
  "PressKeyToolCoreParameters": {
312
318
  "type": "object",
313
319
  "properties": {
@@ -372,158 +378,152 @@
372
378
  "additionalProperties": false,
373
379
  "required": ["annotation", "key", "rationale", "whyThisAnnotation"]
374
380
  },
375
- "RunAccessibilityTestToolCoreParameters": {
381
+ "HandleBrowserDialogToolCoreParameters": {
382
+ "description": "The parameters for handling browser dialogs",
383
+ "type": "object",
384
+ "properties": {
385
+ "text": {
386
+ "description": "If this is a \"confirm\" dialog, a string of \"true\" will accept the dialog and a string of \"false\" will dismiss it.\nHowever, if this is a \"prompt\" dialog, any non-null string will accept it, and a null value will dismiss it.",
387
+ "type": ["string", "null"]
388
+ }
389
+ },
390
+ "additionalProperties": false,
391
+ "required": ["text"]
392
+ },
393
+ "HandleBrowserDialogToolGptParameters": {
394
+ "type": "object",
395
+ "properties": {
396
+ "rationale": {
397
+ "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
398
+ "type": "string"
399
+ },
400
+ "text": {
401
+ "description": "If this is a \"confirm\" dialog, a string of \"true\" will accept the dialog and a string of \"false\" will dismiss it.\nHowever, if this is a \"prompt\" dialog, any non-null string will accept it, and a null value will dismiss it.",
402
+ "type": ["string", "null"]
403
+ }
404
+ },
405
+ "additionalProperties": false,
406
+ "required": ["rationale", "text"]
407
+ },
408
+ "MarkObjectiveCompleteToolCoreParameters": {
409
+ "description": "Parameters for marking an objective as complete",
376
410
  "type": "object",
377
411
  "additionalProperties": false,
378
412
  "required": [],
379
413
  "properties": {}
380
414
  },
381
- "RunAccessibilityTestToolGptParameters": {
415
+ "MarkObjectiveCompleteToolGptParameters": {
416
+ "description": "Parameters for marking an objective as complete",
382
417
  "type": "object",
383
418
  "properties": {
419
+ "details": {
420
+ "description": "Relevant details for the completed objective.",
421
+ "type": "string"
422
+ },
384
423
  "rationale": {
385
424
  "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
386
425
  "type": "string"
387
426
  }
388
427
  },
389
428
  "additionalProperties": false,
390
- "required": ["rationale"]
429
+ "required": ["details", "rationale"]
391
430
  },
392
- "ScrollPageToolCoreParameters": {
431
+ "GoToWebpageToolCoreParameters": {
393
432
  "type": "object",
394
433
  "properties": {
395
- "direction": {
396
- "description": "The direction to scroll - either UP or DOWN",
397
- "enum": ["DOWN", "UP"],
434
+ "url": {
435
+ "description": "The URL to navigate to. Must use the http or https (example is https://google.com).",
398
436
  "type": "string"
399
437
  }
400
438
  },
401
439
  "additionalProperties": false,
402
- "required": ["direction"]
440
+ "required": ["url"]
403
441
  },
404
- "ScrollPageToolGptParameters": {
442
+ "GoToWebpageToolGptParameters": {
405
443
  "type": "object",
406
444
  "properties": {
407
445
  "rationale": {
408
446
  "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
409
447
  "type": "string"
410
448
  },
411
- "direction": {
412
- "description": "The direction to scroll - either UP or DOWN",
413
- "enum": ["DOWN", "UP"],
449
+ "url": {
450
+ "description": "The URL to navigate to. Must use the http or https (example is https://google.com).",
414
451
  "type": "string"
415
452
  }
416
453
  },
417
454
  "additionalProperties": false,
418
- "required": ["direction", "rationale"]
455
+ "required": ["rationale", "url"]
419
456
  },
420
- "AssertToolCoreParameters": {
457
+ "RunAccessibilityTestToolCoreParameters": {
458
+ "type": "object",
459
+ "additionalProperties": false,
460
+ "required": [],
461
+ "properties": {}
462
+ },
463
+ "RunAccessibilityTestToolGptParameters": {
421
464
  "type": "object",
422
465
  "properties": {
423
- "assertionToTestFor": {
424
- "description": "The assertion that will be tested for, using plain English.\n\nExamples:\n- 'Assert that this webpage includes a product summary.'\n- 'Assert there are more than 3 search results.'\n- 'Assert that the webpage title is \"Hello World\".'\n- 'Assert that the theme of the website is in dark mode.'\n\nThe raw assertion text should avoid embedding state about the webpage\nsince the assertion is being evaluated by the tool itself, and the tool\nwill have access to the webpage's content, title, URL, etc.\n\nExamples of bad assertions:\n- 'Assert that the 3 search results is greater than 2.'\n- 'Assert that the first search result (\"banana\") is not \"strawberry\".'\n\nExamples of the bad assertions being rephrased as good assertions:\n- 'Assert that there are more than 2 search results.'\n- 'Assert that the first search result is not \"strawberry\".'",
466
+ "rationale": {
467
+ "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
425
468
  "type": "string"
426
469
  }
427
470
  },
428
471
  "additionalProperties": false,
429
- "required": ["assertionToTestFor"]
472
+ "required": ["rationale"]
430
473
  },
431
- "AssertToolGptParameters": {
474
+ "ScrollPageToolCoreParameters": {
432
475
  "type": "object",
433
476
  "properties": {
434
- "rationale": {
435
- "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
436
- "type": "string"
437
- },
438
- "assertionToTestFor": {
439
- "description": "The assertion that will be tested for, using plain English.\n\nExamples:\n- 'Assert that this webpage includes a product summary.'\n- 'Assert there are more than 3 search results.'\n- 'Assert that the webpage title is \"Hello World\".'\n- 'Assert that the theme of the website is in dark mode.'\n\nThe raw assertion text should avoid embedding state about the webpage\nsince the assertion is being evaluated by the tool itself, and the tool\nwill have access to the webpage's content, title, URL, etc.\n\nExamples of bad assertions:\n- 'Assert that the 3 search results is greater than 2.'\n- 'Assert that the first search result (\"banana\") is not \"strawberry\".'\n\nExamples of the bad assertions being rephrased as good assertions:\n- 'Assert that there are more than 2 search results.'\n- 'Assert that the first search result is not \"strawberry\".'",
477
+ "direction": {
478
+ "description": "The direction to scroll - either UP or DOWN",
479
+ "enum": ["DOWN", "UP"],
440
480
  "type": "string"
441
481
  }
442
482
  },
443
483
  "additionalProperties": false,
444
- "required": ["assertionToTestFor", "rationale"]
484
+ "required": ["direction"]
445
485
  },
446
- "InputTextToolCoreParameters": {
486
+ "ScrollPageToolGptParameters": {
447
487
  "type": "object",
448
488
  "properties": {
449
- "text": {
450
- "description": "The text to input.",
489
+ "rationale": {
490
+ "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
451
491
  "type": "string"
452
492
  },
453
- "finalizeWithSubmit": {
454
- "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
455
- "type": "boolean"
493
+ "direction": {
494
+ "description": "The direction to scroll - either UP or DOWN",
495
+ "enum": ["DOWN", "UP"],
496
+ "type": "string"
456
497
  }
457
498
  },
458
499
  "additionalProperties": false,
459
- "required": ["finalizeWithSubmit", "text"]
500
+ "required": ["direction", "rationale"]
460
501
  },
461
- "SelectorBasedInputTextToolParameters": {
502
+ "AssertToolCoreParameters": {
462
503
  "type": "object",
463
504
  "properties": {
464
- "selector": {
465
- "description": "A query structure used to resolve specific a HTML element in a webpage.",
466
- "type": "object",
467
- "properties": {
468
- "element": {
469
- "description": "An prioritized list of element selectors to use to attempt to resolve the\ndesired element, going from most specific to least specific. The first\nelement selector that is successfully used, wins, and the rest are ignored.",
470
- "type": "array",
471
- "items": {
472
- "type": "string"
473
- }
474
- },
475
- "frame": {
476
- "description": "A selector for the corresponding frame of the element to select.\nIf null, this means the primary frame of the page is used.",
477
- "type": "string"
478
- }
479
- },
480
- "additionalProperties": false,
481
- "required": ["element", "frame"]
482
- },
483
- "text": {
484
- "description": "The text to input.",
505
+ "assertionToTestFor": {
506
+ "description": "The assertion that will be tested for, using plain English.\n\nExamples:\n- 'Assert that this webpage includes a product summary.'\n- 'Assert there are more than 3 search results.'\n- 'Assert that the webpage title is \"Hello World\".'\n- 'Assert that the theme of the website is in dark mode.'\n\nThe raw assertion text should avoid embedding state about the webpage\nsince the assertion is being evaluated by the tool itself, and the tool\nwill have access to the webpage's content, title, URL, etc.\n\nExamples of bad assertions:\n- 'Assert that the 3 search results is greater than 2.'\n- 'Assert that the first search result (\"banana\") is not \"strawberry\".'\n\nExamples of the bad assertions being rephrased as good assertions:\n- 'Assert that there are more than 2 search results.'\n- 'Assert that the first search result is not \"strawberry\".'",
485
507
  "type": "string"
486
- },
487
- "finalizeWithSubmit": {
488
- "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
489
- "type": "boolean"
490
508
  }
491
509
  },
492
510
  "additionalProperties": false,
493
- "required": ["finalizeWithSubmit", "selector", "text"]
511
+ "required": ["assertionToTestFor"]
494
512
  },
495
- "AnnotationBasedInputTextToolParameters": {
513
+ "AssertToolGptParameters": {
496
514
  "type": "object",
497
515
  "properties": {
498
- "whyThisAnnotation": {
499
- "description": "The reason why this particular numbered annotation was chosen.",
500
- "type": "string"
501
- },
502
- "annotation": {
503
- "description": "The numbered annotation of the element to click.",
504
- "type": "string"
505
- },
506
516
  "rationale": {
507
517
  "description": "The reason why this particular action is being taken. It MUST relate to the overall objective.",
508
518
  "type": "string"
509
519
  },
510
- "text": {
511
- "description": "The text to input.",
520
+ "assertionToTestFor": {
521
+ "description": "The assertion that will be tested for, using plain English.\n\nExamples:\n- 'Assert that this webpage includes a product summary.'\n- 'Assert there are more than 3 search results.'\n- 'Assert that the webpage title is \"Hello World\".'\n- 'Assert that the theme of the website is in dark mode.'\n\nThe raw assertion text should avoid embedding state about the webpage\nsince the assertion is being evaluated by the tool itself, and the tool\nwill have access to the webpage's content, title, URL, etc.\n\nExamples of bad assertions:\n- 'Assert that the 3 search results is greater than 2.'\n- 'Assert that the first search result (\"banana\") is not \"strawberry\".'\n\nExamples of the bad assertions being rephrased as good assertions:\n- 'Assert that there are more than 2 search results.'\n- 'Assert that the first search result is not \"strawberry\".'",
512
522
  "type": "string"
513
- },
514
- "finalizeWithSubmit": {
515
- "description": "Attempt to submit the data after inputting the text (i.e. hitting 'Enter' at the end).\nThis can be useful if doing something like using a webpage's search box, etc.",
516
- "type": "boolean"
517
523
  }
518
524
  },
519
525
  "additionalProperties": false,
520
- "required": [
521
- "annotation",
522
- "finalizeWithSubmit",
523
- "rationale",
524
- "text",
525
- "whyThisAnnotation"
526
- ]
526
+ "required": ["assertionToTestFor", "rationale"]
527
527
  },
528
528
  "AnalyzePageTextToolCoreParameters": {
529
529
  "type": "object",
@@ -1962,107 +1962,6 @@
1962
1962
  "additionalProperties": false,
1963
1963
  "required": ["rationale", "text"]
1964
1964
  },
1965
- "ToolParameters": {
1966
- "anyOf": [
1967
- {
1968
- "type": "object",
1969
- "properties": {
1970
- "_type": {},
1971
- "_output": {},
1972
- "_input": {},
1973
- "_def": {},
1974
- "description": {
1975
- "type": "string"
1976
- },
1977
- "~standard": {
1978
- "description": "The Standard Schema properties interface.",
1979
- "type": "object",
1980
- "properties": {
1981
- "version": {
1982
- "description": "The version number of the standard.",
1983
- "type": "number",
1984
- "const": 1
1985
- },
1986
- "vendor": {
1987
- "description": "The vendor name of the schema library.",
1988
- "type": "string"
1989
- },
1990
- "validate": {
1991
- "description": "Validates unknown input values.",
1992
- "type": "object",
1993
- "additionalProperties": false
1994
- },
1995
- "types": {
1996
- "description": "Inferred types associated with the schema.",
1997
- "type": "object",
1998
- "properties": {
1999
- "input": {
2000
- "description": "The input type of the schema."
2001
- },
2002
- "output": {
2003
- "description": "The output type of the schema."
2004
- }
2005
- },
2006
- "additionalProperties": false,
2007
- "required": ["input", "output"]
2008
- }
2009
- },
2010
- "additionalProperties": false,
2011
- "required": ["validate", "vendor", "version"]
2012
- },
2013
- "spa": {
2014
- "description": "Alias of safeParseAsync",
2015
- "type": "object",
2016
- "additionalProperties": false
2017
- }
2018
- },
2019
- "additionalProperties": false,
2020
- "required": [
2021
- "_def",
2022
- "_input",
2023
- "_output",
2024
- "_type",
2025
- "description",
2026
- "spa",
2027
- "~standard"
2028
- ]
2029
- },
2030
- {
2031
- "additionalProperties": false,
2032
- "type": "object",
2033
- "properties": {
2034
- "validate": {
2035
- "description": "Optional. Validates that the structure of a value matches this schema,\nand returns a typed version of the value if it does.",
2036
- "type": "object",
2037
- "additionalProperties": false
2038
- },
2039
- "__@validatorSymbol@19388": {
2040
- "description": "Used to mark validator functions so we can support both Zod and custom schemas.",
2041
- "type": "boolean",
2042
- "const": true
2043
- },
2044
- "_type": {
2045
- "description": "Schema type for inference."
2046
- },
2047
- "jsonSchema": {
2048
- "$ref": "#/definitions/JSONSchema7",
2049
- "description": "The JSON Schema for the schema. It is passed to the providers."
2050
- },
2051
- "__@schemaSymbol@19393": {
2052
- "description": "Used to mark schemas so we can support both Zod and custom schemas.",
2053
- "type": "boolean",
2054
- "const": true
2055
- }
2056
- },
2057
- "required": [
2058
- "__@schemaSymbol@19393",
2059
- "__@validatorSymbol@19388",
2060
- "_type",
2061
- "jsonSchema"
2062
- ]
2063
- }
2064
- ]
2065
- },
2066
1965
  "AggregateExtractedStreetviewDataToolCoreParameters": {
2067
1966
  "type": "object",
2068
1967
  "additionalProperties": false,
@@ -1 +1 @@
1
- 1087
1
+ 1107
@@ -32,7 +32,7 @@
32
32
  return `'${value}'`;
33
33
  }
34
34
 
35
- // If the string has single quotes but no double quotes, wrap in double quotes
35
+ // If the string has no double quotes, wrap in double quotes
36
36
  if (!value.includes('"')) {
37
37
  return `"${value}"`;
38
38
  }
@@ -91,9 +91,24 @@
91
91
  selectors.add(selector),
92
92
  );
93
93
 
94
+ // Generate DOM position-based selectors
95
+ this.getDOMPositionSelectors().forEach((selector) =>
96
+ selectors.add(selector),
97
+ );
98
+
94
99
  // Combine selectors for robustness
95
100
  this.getCombinedSelector().forEach((selector) => selectors.add(selector));
96
101
 
102
+ function selectorTiebreakerPriority(sel) {
103
+ // highest-to-lowest: aria-label, placeholder, text-based XPath, DOM position, id, other
104
+ if (/\[aria-label\s*=/.test(sel) || /@aria-label/.test(sel)) return 0;
105
+ if (/\[placeholder\s*=/.test(sel) || /@placeholder/.test(sel)) return 1;
106
+ if (sel.startsWith('//')) return 2;
107
+ if (sel.includes(' > ')) return 3; // DOM position selector
108
+ if (/^#/.test(sel)) return 4;
109
+ return 5;
110
+ }
111
+
97
112
  const rankedSelectors = Array.from(selectors)
98
113
  .map((selector) => {
99
114
  try {
@@ -104,9 +119,18 @@
104
119
  }
105
120
  })
106
121
  .filter((a) => a !== null && a.count !== 0)
107
- .sort((a, b) => a.count - b.count);
122
+ .sort((a, b) => {
123
+ // 1. fewer matches -> better
124
+ if (a.count !== b.count) return a.count - b.count;
125
+ // 2. tie-break on priority class
126
+ return (
127
+ selectorTiebreakerPriority(a.selector) -
128
+ selectorTiebreakerPriority(b.selector)
129
+ );
130
+ })
131
+ .map((a) => a.selector);
108
132
 
109
- return rankedSelectors.map((a) => a.selector);
133
+ return rankedSelectors;
110
134
  }
111
135
 
112
136
  getIdSelector() {
@@ -243,6 +267,40 @@
243
267
  return [];
244
268
  }
245
269
 
270
+ getDOMPositionSelectors() {
271
+ const selectors = [];
272
+
273
+ // Generate full DOM position-based selector without depth limit
274
+ let currentElement = this.element;
275
+ let path = [];
276
+
277
+ // Build the complete path from the element up to html
278
+ while (currentElement && currentElement !== document) {
279
+ let tagName = currentElement.tagName.toLowerCase();
280
+ const parent = currentElement.parentElement;
281
+
282
+ if (parent) {
283
+ const siblings = Array.from(parent.children).filter(
284
+ (child) => child.tagName.toLowerCase() === tagName,
285
+ );
286
+ if (siblings.length > 1) {
287
+ const index = siblings.indexOf(currentElement) + 1;
288
+ tagName += `:nth-of-type(${index})`;
289
+ }
290
+ }
291
+
292
+ path.unshift(tagName);
293
+ currentElement = currentElement.parentElement;
294
+ }
295
+
296
+ // Create the full selector string with ">" separators
297
+ if (path.length > 1) {
298
+ selectors.push(path.join(' > '));
299
+ }
300
+
301
+ return selectors;
302
+ }
303
+
246
304
  getCombinedSelector() {
247
305
  const classSelector = this.getClassSelector()[0];
248
306
  return classSelector ? [`${this.getTagSelector()}${classSelector}`] : [];