browsergym-workarena 0.1.0rc7__py3-none-any.whl → 0.2.1__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.
- browsergym/workarena/__init__.py +3 -2
- browsergym/workarena/api/ui_themes.py +35 -0
- browsergym/workarena/api/user.py +153 -0
- browsergym/workarena/api/utils.py +1 -1
- browsergym/workarena/config.py +43 -1
- browsergym/workarena/data_files/setup_files/ui_themes/workarena_themes.xml +2313 -0
- browsergym/workarena/data_files/task_configs/all_menu.json +94 -94
- browsergym/workarena/data_files/task_configs/dashboard_retrieval_minmax_task.json +1 -0
- browsergym/workarena/data_files/task_configs/dashboard_retrieval_value_task.json +1 -0
- browsergym/workarena/data_files/task_configs/filter_service_catalog_item_list_task.json +7985 -7981
- browsergym/workarena/data_files/task_configs/impersonation_users.json +2 -2
- browsergym/workarena/data_files/task_configs/report_retrieval_minmax_task.json +1 -0
- browsergym/workarena/data_files/task_configs/report_retrieval_value_task.json +1 -0
- browsergym/workarena/install.py +620 -155
- browsergym/workarena/tasks/base.py +85 -26
- browsergym/workarena/tasks/dashboard.py +620 -0
- browsergym/workarena/tasks/form.py +121 -85
- browsergym/workarena/tasks/knowledge.py +30 -14
- browsergym/workarena/tasks/list.py +121 -67
- browsergym/workarena/tasks/navigation.py +18 -16
- browsergym/workarena/tasks/scripts/generate_dashboard_configs.py +272 -0
- browsergym/workarena/tasks/scripts/generate_forms.py +2 -2
- browsergym/workarena/tasks/scripts/list.py +2 -2
- browsergym/workarena/tasks/scripts/validate.py +2 -2
- browsergym/workarena/tasks/service_catalog.py +106 -74
- browsergym/workarena/tasks/utils/form.py +5 -3
- browsergym/workarena/tasks/utils/js_utils.js +123 -2
- browsergym/workarena/tasks/utils/string.py +15 -0
- browsergym/workarena/tasks/utils/utils.py +20 -0
- browsergym/workarena/utils.py +31 -2
- {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/METADATA +15 -5
- {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/RECORD +35 -24
- {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/WHEEL +1 -1
- {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/entry_points.txt +0 -0
- {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -8,17 +8,21 @@ import logging
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import playwright.sync_api
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from abc import ABC, abstractmethod
|
|
12
|
+
from copy import deepcopy
|
|
13
|
+
from typing import Dict, List, Optional, Tuple
|
|
12
14
|
from uuid import uuid4
|
|
13
|
-
from urllib
|
|
15
|
+
from urllib import parse
|
|
14
16
|
|
|
15
17
|
from browsergym.core.task import AbstractBrowserTask
|
|
18
|
+
from ..api.user import create_user
|
|
19
|
+
from ..api.utils import table_api_call
|
|
16
20
|
from ..config import SNOW_BROWSER_TIMEOUT, SNOW_JS_UTILS_FILEPATH
|
|
17
|
-
from ..utils import impersonate_user,
|
|
21
|
+
from ..utils import impersonate_user, url_login
|
|
18
22
|
from ..instance import SNowInstance
|
|
19
23
|
|
|
20
24
|
|
|
21
|
-
class AbstractServiceNowTask(AbstractBrowserTask):
|
|
25
|
+
class AbstractServiceNowTask(AbstractBrowserTask, ABC):
|
|
22
26
|
"""
|
|
23
27
|
A base class for tasks that interacts with the ServiceNow instance
|
|
24
28
|
|
|
@@ -26,6 +30,7 @@ class AbstractServiceNowTask(AbstractBrowserTask):
|
|
|
26
30
|
|
|
27
31
|
def __init__(
|
|
28
32
|
self,
|
|
33
|
+
seed: int,
|
|
29
34
|
start_rel_url: str,
|
|
30
35
|
instance: SNowInstance = None,
|
|
31
36
|
final_rel_url: Optional[str] = None,
|
|
@@ -36,37 +41,44 @@ class AbstractServiceNowTask(AbstractBrowserTask):
|
|
|
36
41
|
|
|
37
42
|
Parameters:
|
|
38
43
|
-----------
|
|
44
|
+
seed: int
|
|
45
|
+
Random seed
|
|
39
46
|
instance: SNowInstance
|
|
40
47
|
The ServiceNow instance in which the task will be performed
|
|
41
48
|
start_url: str
|
|
42
49
|
The URL for the starting page of the task
|
|
43
50
|
final_url: str (optional)
|
|
44
51
|
The URL for the final page of the task (default: uses the value of base_url)
|
|
45
|
-
username: str (optional)
|
|
46
|
-
The username of the user to impersonate to run the task (default: admin)
|
|
47
52
|
|
|
48
53
|
"""
|
|
54
|
+
super().__init__(seed)
|
|
55
|
+
|
|
56
|
+
# task properties, will be used to set up the browsergym environment
|
|
57
|
+
self.viewport = {"width": 1280, "height": 720}
|
|
58
|
+
self.slow_mo = 1000 # ms
|
|
59
|
+
self.timeout = 10000 # ms
|
|
60
|
+
|
|
49
61
|
self.instance = instance if instance is not None else SNowInstance()
|
|
50
62
|
self.start_url = self.instance.snow_url + start_rel_url
|
|
51
|
-
self.username = username
|
|
52
63
|
|
|
53
64
|
if final_rel_url is not None:
|
|
54
65
|
self.final_url = self.instance.snow_url + final_rel_url
|
|
55
66
|
else:
|
|
56
67
|
self.final_url = self.start_url
|
|
57
|
-
self.final_url_ = urlparse(self.final_url)
|
|
58
|
-
|
|
59
|
-
def _add_init_scripts_to_context_and_reload(
|
|
60
|
-
self, page: playwright.sync_api.Page, scripts: List[str]
|
|
61
|
-
) -> None:
|
|
62
|
-
for script in scripts:
|
|
63
|
-
page.context.add_init_script(script)
|
|
64
|
-
page.reload()
|
|
68
|
+
self.final_url_ = parse.urlparse(self.final_url)
|
|
65
69
|
|
|
66
70
|
def cheat(self, page: playwright.sync_api.Page, chat_messages: list[str]) -> None:
|
|
67
71
|
# Don't call super cheat function because it's not implemented at the base level
|
|
68
72
|
logging.debug("Cheat is solving the task")
|
|
69
73
|
|
|
74
|
+
def get_init_scripts(self) -> List[str]:
|
|
75
|
+
"""
|
|
76
|
+
Get the initialization scripts for the task. These are javascript scripts that will be run
|
|
77
|
+
on any page and iframe that is loaded during the task.
|
|
78
|
+
|
|
79
|
+
"""
|
|
80
|
+
return []
|
|
81
|
+
|
|
70
82
|
@classmethod
|
|
71
83
|
def get_task_id(cls):
|
|
72
84
|
# Get the class name and remove the word 'Task' from the end if it exists
|
|
@@ -77,32 +89,79 @@ class AbstractServiceNowTask(AbstractBrowserTask):
|
|
|
77
89
|
).lstrip("-")
|
|
78
90
|
return f"workarena.servicenow.{formatted_name}"
|
|
79
91
|
|
|
80
|
-
def
|
|
81
|
-
|
|
92
|
+
def setup(self, page: playwright.sync_api.Page, do_start=True) -> tuple[str, dict]:
|
|
93
|
+
"""
|
|
94
|
+
Set up the task
|
|
95
|
+
|
|
96
|
+
Parameters:
|
|
97
|
+
-----------
|
|
98
|
+
page: playwright.sync_api.Page
|
|
99
|
+
The Playwright page object
|
|
100
|
+
do_start: bool
|
|
101
|
+
Whether to start the task or not (including navigating to start page) (default: True)
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
logging.debug("Setting up the base task")
|
|
105
|
+
|
|
106
|
+
# Keep the page for client-side validation
|
|
107
|
+
self.page = page
|
|
82
108
|
|
|
83
109
|
# Set the page timeout
|
|
84
110
|
page.set_default_timeout(SNOW_BROWSER_TIMEOUT)
|
|
85
111
|
|
|
112
|
+
# Set the task's unique ID
|
|
113
|
+
self.unique_id = str(uuid4())
|
|
114
|
+
|
|
115
|
+
# Configure the task
|
|
116
|
+
goal, info = self.setup_goal(page=page)
|
|
117
|
+
|
|
86
118
|
# Load a few utility functions for init scripts
|
|
87
119
|
page.add_init_script(path=SNOW_JS_UTILS_FILEPATH)
|
|
88
120
|
|
|
89
|
-
#
|
|
90
|
-
self.
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
# Add the initialization scripts to the page context
|
|
122
|
+
for script in self.get_init_scripts():
|
|
123
|
+
page.context.add_init_script(script)
|
|
124
|
+
|
|
125
|
+
# Create a new user to run the task
|
|
126
|
+
self._base_initial_instance = self.instance
|
|
127
|
+
self._base_user_name, self._base_user_password, self._base_user_sysid = create_user(
|
|
128
|
+
self.instance
|
|
129
|
+
)
|
|
130
|
+
self.instance = deepcopy(self.instance)
|
|
131
|
+
self.instance.snow_credentials = (self._base_user_name, self._base_user_password)
|
|
132
|
+
|
|
133
|
+
# Start the task if requested
|
|
134
|
+
if do_start:
|
|
135
|
+
self.start(page)
|
|
136
|
+
|
|
137
|
+
return goal, info
|
|
138
|
+
|
|
139
|
+
@abstractmethod
|
|
140
|
+
def setup_goal(self, page: playwright.sync_api.Page) -> tuple[str, dict]:
|
|
141
|
+
"""
|
|
142
|
+
Setup the task configuration and produce the goal
|
|
143
|
+
|
|
144
|
+
"""
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
def start(self, page: playwright.sync_api.Page) -> None:
|
|
148
|
+
logging.debug("Navigating to task start page")
|
|
93
149
|
|
|
94
150
|
# Authenticate
|
|
95
|
-
|
|
151
|
+
url_login(
|
|
96
152
|
instance=self.instance,
|
|
97
153
|
page=page,
|
|
98
154
|
)
|
|
99
155
|
|
|
100
|
-
# Impersonate if needed
|
|
101
|
-
if self.username != "admin":
|
|
102
|
-
impersonate_user(self.username, page)
|
|
103
|
-
|
|
104
156
|
# Navigate to the task's url
|
|
105
157
|
page.goto(self.start_url)
|
|
106
158
|
|
|
107
159
|
def teardown(self) -> None:
|
|
108
160
|
logging.debug("Tearing down the task")
|
|
161
|
+
|
|
162
|
+
# Delete the user
|
|
163
|
+
table_api_call(
|
|
164
|
+
instance=self._base_initial_instance,
|
|
165
|
+
table=f"sys_user/{self._base_user_sysid}",
|
|
166
|
+
method="DELETE",
|
|
167
|
+
)
|