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.
Files changed (35) hide show
  1. browsergym/workarena/__init__.py +3 -2
  2. browsergym/workarena/api/ui_themes.py +35 -0
  3. browsergym/workarena/api/user.py +153 -0
  4. browsergym/workarena/api/utils.py +1 -1
  5. browsergym/workarena/config.py +43 -1
  6. browsergym/workarena/data_files/setup_files/ui_themes/workarena_themes.xml +2313 -0
  7. browsergym/workarena/data_files/task_configs/all_menu.json +94 -94
  8. browsergym/workarena/data_files/task_configs/dashboard_retrieval_minmax_task.json +1 -0
  9. browsergym/workarena/data_files/task_configs/dashboard_retrieval_value_task.json +1 -0
  10. browsergym/workarena/data_files/task_configs/filter_service_catalog_item_list_task.json +7985 -7981
  11. browsergym/workarena/data_files/task_configs/impersonation_users.json +2 -2
  12. browsergym/workarena/data_files/task_configs/report_retrieval_minmax_task.json +1 -0
  13. browsergym/workarena/data_files/task_configs/report_retrieval_value_task.json +1 -0
  14. browsergym/workarena/install.py +620 -155
  15. browsergym/workarena/tasks/base.py +85 -26
  16. browsergym/workarena/tasks/dashboard.py +620 -0
  17. browsergym/workarena/tasks/form.py +121 -85
  18. browsergym/workarena/tasks/knowledge.py +30 -14
  19. browsergym/workarena/tasks/list.py +121 -67
  20. browsergym/workarena/tasks/navigation.py +18 -16
  21. browsergym/workarena/tasks/scripts/generate_dashboard_configs.py +272 -0
  22. browsergym/workarena/tasks/scripts/generate_forms.py +2 -2
  23. browsergym/workarena/tasks/scripts/list.py +2 -2
  24. browsergym/workarena/tasks/scripts/validate.py +2 -2
  25. browsergym/workarena/tasks/service_catalog.py +106 -74
  26. browsergym/workarena/tasks/utils/form.py +5 -3
  27. browsergym/workarena/tasks/utils/js_utils.js +123 -2
  28. browsergym/workarena/tasks/utils/string.py +15 -0
  29. browsergym/workarena/tasks/utils/utils.py +20 -0
  30. browsergym/workarena/utils.py +31 -2
  31. {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/METADATA +15 -5
  32. {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/RECORD +35 -24
  33. {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/WHEEL +1 -1
  34. {browsergym_workarena-0.1.0rc7.dist-info → browsergym_workarena-0.2.1.dist-info}/entry_points.txt +0 -0
  35. {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 typing import Optional, List, Tuple
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.parse import urlparse
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, ui_login
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 pre_setup(self, seed: int, page: playwright.sync_api.Page):
81
- logging.debug("Setting up base task")
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
- # Set the task's unique ID
90
- self.unique_id = str(uuid4())
91
- self.random = np.random.RandomState(seed)
92
- self.page = page # Keep the page for client-side validation
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
- ui_login(
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
+ )