browsergym-workarena 0.2.0__py3-none-any.whl → 0.3.0__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 +13 -1
- browsergym/workarena/api/category.py +74 -0
- browsergym/workarena/api/change_request.py +87 -0
- browsergym/workarena/api/computer_asset.py +90 -0
- browsergym/workarena/api/cost_center.py +19 -0
- browsergym/workarena/api/expense_line.py +89 -0
- browsergym/workarena/api/incident.py +45 -0
- browsergym/workarena/api/knowledge.py +29 -0
- browsergym/workarena/api/problem.py +90 -0
- browsergym/workarena/api/report.py +183 -0
- browsergym/workarena/api/requested_items.py +63 -0
- browsergym/workarena/api/user.py +11 -8
- browsergym/workarena/api/utils.py +47 -3
- browsergym/workarena/config.py +21 -1
- browsergym/workarena/data_files/setup_files/forms/expected_incident_form_fields.json +1 -1
- browsergym/workarena/data_files/setup_files/forms/expected_request_item_form_fields.json +1 -0
- browsergym/workarena/data_files/setup_files/knowledge/protocols.json +46 -0
- browsergym/workarena/data_files/setup_files/knowledge/test.html +1 -0
- browsergym/workarena/data_files/setup_files/lists/expected_asset_list_columns.json +2 -24
- browsergym/workarena/data_files/setup_files/lists/expected_change_request_list_columns.json +4 -40
- browsergym/workarena/data_files/setup_files/lists/expected_expense_line_list_columns.json +12 -0
- browsergym/workarena/data_files/setup_files/lists/expected_hardware_list_columns.json +1 -42
- browsergym/workarena/data_files/setup_files/lists/expected_incident_list_columns.json +2 -18
- browsergym/workarena/data_files/setup_files/lists/expected_problem_list_columns.json +12 -0
- browsergym/workarena/data_files/setup_files/lists/expected_requested_items_list_columns.json +12 -0
- browsergym/workarena/data_files/setup_files/lists/expected_service_catalog_list_columns.json +2 -19
- browsergym/workarena/data_files/setup_files/lists/expected_user_list_columns.json +3 -50
- browsergym/workarena/data_files/task_configs/all_menu.json +95 -95
- browsergym/workarena/data_files/task_configs/dashboard_retrieval_minmax_task.json +1 -1
- browsergym/workarena/data_files/task_configs/dashboard_retrieval_value_task.json +1 -1
- browsergym/workarena/data_files/task_configs/filter_service_catalog_item_list_task.json +7986 -7982
- browsergym/workarena/data_files/task_configs/impersonation_users.json +3 -3
- browsergym/workarena/data_files/task_configs/report_retrieval_minmax_task.json +1 -1
- browsergym/workarena/data_files/task_configs/report_retrieval_value_task.json +1 -1
- browsergym/workarena/human_eval/console.js +176 -0
- browsergym/workarena/human_eval/tool.py +366 -0
- browsergym/workarena/install.py +81 -20
- browsergym/workarena/tasks/base.py +55 -20
- browsergym/workarena/tasks/comp_building_block.py +4 -0
- browsergym/workarena/tasks/compositional/__init__.py +76 -0
- browsergym/workarena/tasks/compositional/base.py +364 -0
- browsergym/workarena/tasks/compositional/dash_do_base.py +1366 -0
- browsergym/workarena/tasks/compositional/dash_do_catalog.py +1127 -0
- browsergym/workarena/tasks/compositional/dash_do_catalog_infeasible.py +2047 -0
- browsergym/workarena/tasks/compositional/dash_do_create_incident.py +403 -0
- browsergym/workarena/tasks/compositional/dash_do_create_incident_infeasible.py +278 -0
- browsergym/workarena/tasks/compositional/dash_do_create_problem.py +336 -0
- browsergym/workarena/tasks/compositional/dash_do_create_problem_infeasible.py +235 -0
- browsergym/workarena/tasks/compositional/dash_do_filter.py +1600 -0
- browsergym/workarena/tasks/compositional/dash_do_request_item.py +1315 -0
- browsergym/workarena/tasks/compositional/dash_do_request_item_infeasible.py +693 -0
- browsergym/workarena/tasks/compositional/delete_record.py +341 -0
- browsergym/workarena/tasks/compositional/edit_knowledge_base.py +457 -0
- browsergym/workarena/tasks/compositional/expense_management.py +598 -0
- browsergym/workarena/tasks/compositional/filter_and_do.py +139 -0
- browsergym/workarena/tasks/compositional/find_and_order_item.py +345 -0
- browsergym/workarena/tasks/compositional/manage_change_request_schedule.py +1417 -0
- browsergym/workarena/tasks/compositional/mark_duplicate_problems.py +499 -0
- browsergym/workarena/tasks/compositional/maximize_investment_return.py +1763 -0
- browsergym/workarena/tasks/compositional/navigate_and_do.py +1151 -0
- browsergym/workarena/tasks/compositional/navigate_and_do_infeasible.py +2100 -0
- browsergym/workarena/tasks/compositional/offboard_user.py +207 -0
- browsergym/workarena/tasks/compositional/onboard_user.py +226 -0
- browsergym/workarena/tasks/compositional/update_task.py +145 -0
- browsergym/workarena/tasks/compositional/utils/curriculum.py +215 -0
- browsergym/workarena/tasks/compositional/utils/infeasible_configs.py +151 -0
- browsergym/workarena/tasks/compositional/utils/knapsack.py +192 -0
- browsergym/workarena/tasks/compositional/warranty_check.py +227 -0
- browsergym/workarena/tasks/compositional/work_assignment.py +804 -0
- browsergym/workarena/tasks/compositional/workload_balancing.py +396 -0
- browsergym/workarena/tasks/dashboard.py +188 -8
- browsergym/workarena/tasks/form.py +1024 -232
- browsergym/workarena/tasks/knowledge.py +216 -25
- browsergym/workarena/tasks/list.py +519 -102
- browsergym/workarena/tasks/mark_duplicate_problem.py +171 -0
- browsergym/workarena/tasks/navigation.py +55 -13
- browsergym/workarena/tasks/scripts/extract_all_menu_items.py +9 -2
- browsergym/workarena/tasks/scripts/generate_dashboard_configs.py +6 -5
- browsergym/workarena/tasks/scripts/service_catalog.py +2 -1
- browsergym/workarena/tasks/scripts/validate.py +8 -2
- browsergym/workarena/tasks/send_chat_message.py +90 -0
- browsergym/workarena/tasks/service_catalog.py +94 -26
- browsergym/workarena/tasks/utils/form.py +1 -4
- browsergym/workarena/tasks/utils/private_tasks.py +63 -0
- browsergym/workarena/tasks/utils/utils.py +13 -0
- {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/METADATA +27 -20
- browsergym_workarena-0.3.0.dist-info/RECORD +138 -0
- {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/entry_points.txt +1 -0
- browsergym_workarena-0.2.0.dist-info/RECORD +0 -85
- {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/WHEEL +0 -0
- {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
from faker import Faker
|
|
4
|
+
|
|
5
|
+
fake = Faker()
|
|
6
|
+
|
|
7
|
+
from playwright.sync_api._generated import Page
|
|
8
|
+
|
|
9
|
+
from .base import CompositionalTask, HumanEvalTask
|
|
10
|
+
|
|
11
|
+
from ..base import AbstractServiceNowTask
|
|
12
|
+
from ..knowledge import KnowledgeBaseSearchTask
|
|
13
|
+
from ..list import ExtractListInfoTask, FilterHardwareListTask
|
|
14
|
+
from ..navigation import AllMenuTask
|
|
15
|
+
|
|
16
|
+
from ...api.computer_asset import create_computer_asset
|
|
17
|
+
from ...api.user import create_user
|
|
18
|
+
from ...api.utils import db_delete_from_table, table_api_call
|
|
19
|
+
from ...instance import SNowInstance
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GetWarrantyExpirationDateTask(CompositionalTask, HumanEvalTask):
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
seed: int = None,
|
|
26
|
+
instance: SNowInstance = None,
|
|
27
|
+
fixed_config: list[AbstractServiceNowTask] = None,
|
|
28
|
+
level: int = 2,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Create a compositional task with specific subtasks
|
|
32
|
+
|
|
33
|
+
Parameters:
|
|
34
|
+
-----------
|
|
35
|
+
instance: SNowInstance
|
|
36
|
+
The ServiceNow instance to run the task on.
|
|
37
|
+
fixed_config: list[AbstractServiceNowTask]
|
|
38
|
+
A list of subtasks
|
|
39
|
+
level: int
|
|
40
|
+
The level of the task; choice between 2 and 3. L2 will have all the info in the the goal and start in the SNOW home page.
|
|
41
|
+
L3 will start in a private task page describing the information needed to complete the task and the related company protocol
|
|
42
|
+
to complete it.
|
|
43
|
+
Attributes:
|
|
44
|
+
-----------
|
|
45
|
+
task_description: str
|
|
46
|
+
The start of the task description to be completed. e.g. "Referring to company protocol '[company_protocol]', onboard user with the following information: \n"
|
|
47
|
+
short_description: str
|
|
48
|
+
A short description of the task to be completed. e.g. "Find the warranty expiration date for John Doe's laptop"
|
|
49
|
+
"""
|
|
50
|
+
assert level in [2, 3], "Level must be either 2 or 3"
|
|
51
|
+
self.level = level
|
|
52
|
+
self.protocol_name = "Finding the warranty expiration for a user's laptop"
|
|
53
|
+
super().__init__(
|
|
54
|
+
seed=seed,
|
|
55
|
+
instance=instance,
|
|
56
|
+
fixed_config=fixed_config,
|
|
57
|
+
level=level,
|
|
58
|
+
protocol_name=self.protocol_name,
|
|
59
|
+
)
|
|
60
|
+
self.task_description = None
|
|
61
|
+
self.short_description = None
|
|
62
|
+
self.user_sys_id = None
|
|
63
|
+
self.user_name = None
|
|
64
|
+
self.user_full_name = None
|
|
65
|
+
self.laptop_sys_id = None
|
|
66
|
+
self.warranty_expiration_date = None
|
|
67
|
+
|
|
68
|
+
def setup_goal(self, page: Page) -> tuple[str, dict]:
|
|
69
|
+
# Create a user and a laptop for the user
|
|
70
|
+
self._create_user_and_laptop()
|
|
71
|
+
|
|
72
|
+
# Sample a configuration
|
|
73
|
+
config = self.fixed_config if self.fixed_config else self._get_config()
|
|
74
|
+
|
|
75
|
+
# Get the task description
|
|
76
|
+
self.short_description = (
|
|
77
|
+
f"Find the warranty expiration date for {self.user_full_name}'s laptop"
|
|
78
|
+
)
|
|
79
|
+
self.task_description = f'Refer to company protocol "{self.protocol_name}" (located in the "Company Protocols" knowledge base) for the steps to find the Warranty expiration date for {self.user_full_name}\'s laptop.\n \n'
|
|
80
|
+
|
|
81
|
+
goal, info = super().setup_goal(page=page, config=config)
|
|
82
|
+
|
|
83
|
+
return goal, info
|
|
84
|
+
|
|
85
|
+
def _get_config(self) -> list[AbstractServiceNowTask]:
|
|
86
|
+
navigate_to_protocol_subtask = [
|
|
87
|
+
# Navigate to the KB
|
|
88
|
+
AllMenuTask(
|
|
89
|
+
instance=self.instance,
|
|
90
|
+
fixed_config={
|
|
91
|
+
"application": "Self-Service",
|
|
92
|
+
"module": "Knowledge",
|
|
93
|
+
"url": "/now/nav/ui/classic/params/target/%24knowledge.do",
|
|
94
|
+
},
|
|
95
|
+
is_validated=False,
|
|
96
|
+
used_in_level_2=False,
|
|
97
|
+
),
|
|
98
|
+
# Find the protocol for on-boarding a new user
|
|
99
|
+
KnowledgeBaseSearchTask(
|
|
100
|
+
instance=self.instance,
|
|
101
|
+
fixed_config={
|
|
102
|
+
"alternative_answers": [],
|
|
103
|
+
"item": f"{self.protocol_name}",
|
|
104
|
+
"question": f'Can you find the "{self.protocol_name}" Protocol in the Knowledge Base?',
|
|
105
|
+
"value": "",
|
|
106
|
+
},
|
|
107
|
+
is_validated=False,
|
|
108
|
+
used_in_level_2=False,
|
|
109
|
+
),
|
|
110
|
+
]
|
|
111
|
+
navigate_to_hardware_asset_and_filter = [
|
|
112
|
+
# Navigate to the hardware asset list
|
|
113
|
+
AllMenuTask(
|
|
114
|
+
instance=self.instance,
|
|
115
|
+
fixed_config={
|
|
116
|
+
"application": "Asset",
|
|
117
|
+
"module": "Portfolios > Hardware Assets",
|
|
118
|
+
"url": "/now/nav/ui/classic/params/target/alm_hardware_list.do",
|
|
119
|
+
},
|
|
120
|
+
is_validated=False,
|
|
121
|
+
used_in_level_2=True,
|
|
122
|
+
),
|
|
123
|
+
# Filter the hardware asset list
|
|
124
|
+
FilterHardwareListTask(
|
|
125
|
+
instance=self.instance,
|
|
126
|
+
fixed_config={
|
|
127
|
+
"filter_columns": ["assigned_to"],
|
|
128
|
+
"filter_kind": "AND",
|
|
129
|
+
"filter_values": [f"{self.user_full_name}"],
|
|
130
|
+
},
|
|
131
|
+
is_validated=False,
|
|
132
|
+
used_in_level_2=True,
|
|
133
|
+
),
|
|
134
|
+
]
|
|
135
|
+
extract_warranty_subtask = [
|
|
136
|
+
ExtractListInfoTask(
|
|
137
|
+
instance=self.instance,
|
|
138
|
+
unique_field_name="assigned_to",
|
|
139
|
+
fixed_config={
|
|
140
|
+
"start_rel_url": "",
|
|
141
|
+
"fields": {
|
|
142
|
+
"assigned_to": "Assigned to",
|
|
143
|
+
"warranty_expiration": "Warranty expiration",
|
|
144
|
+
},
|
|
145
|
+
"expected_values": [
|
|
146
|
+
{
|
|
147
|
+
"assigned_to": f"{self.user_full_name}",
|
|
148
|
+
"warranty_expiration": f"{self.warranty_expiration_date}",
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
list_name="Hardware Assets",
|
|
153
|
+
list_url="/now/nav/ui/classic/params/target/alm_hardware_list.do",
|
|
154
|
+
table_name="alm_hardware",
|
|
155
|
+
is_validated=True,
|
|
156
|
+
used_in_level_2=True,
|
|
157
|
+
),
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
config = (
|
|
161
|
+
navigate_to_protocol_subtask
|
|
162
|
+
+ navigate_to_hardware_asset_and_filter
|
|
163
|
+
+ extract_warranty_subtask
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
return config
|
|
167
|
+
|
|
168
|
+
def _create_user_and_laptop(self) -> None:
|
|
169
|
+
"""
|
|
170
|
+
Creates a user and a laptop for the user. The laptop model is randomly selected from the available computer models.
|
|
171
|
+
Sets the user_sys_id, laptop_sys_id, user_name and warranty_expiration_date attributes.
|
|
172
|
+
"""
|
|
173
|
+
# Generate random name for the user
|
|
174
|
+
first_name = fake.first_name() + "-" + fake.first_name()
|
|
175
|
+
last_name = fake.last_name() + "-" + fake.last_name()
|
|
176
|
+
self.user_full_name = first_name + " " + last_name
|
|
177
|
+
# Create user
|
|
178
|
+
self.user_name, _, self.user_sys_id = create_user(
|
|
179
|
+
instance=self.instance, first_name=first_name, last_name=last_name, random=self.random
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
assert self.user_sys_id, f"Failed to create user {first_name} {last_name}"
|
|
183
|
+
self.warranty_expiration_date = str(fake.date_between(start_date="-1y", end_date="+1y"))
|
|
184
|
+
asset_tag = "P" + str(id(self) % (10**8)).zfill(8)
|
|
185
|
+
(
|
|
186
|
+
computer_sys_id,
|
|
187
|
+
_,
|
|
188
|
+
_,
|
|
189
|
+
) = create_computer_asset(
|
|
190
|
+
instance=self.instance,
|
|
191
|
+
asset_tag=asset_tag,
|
|
192
|
+
warranty_expiration_date=self.warranty_expiration_date,
|
|
193
|
+
user_sys_id=self.user_sys_id,
|
|
194
|
+
random=self.random,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
assert computer_sys_id, f"Failed to create hardware asset {asset_tag}"
|
|
198
|
+
self.laptop_sys_id = computer_sys_id
|
|
199
|
+
|
|
200
|
+
def teardown(self) -> None:
|
|
201
|
+
# Delete the user and the laptop
|
|
202
|
+
user_record_exists = table_api_call(
|
|
203
|
+
instance=self.instance,
|
|
204
|
+
table="sys_user",
|
|
205
|
+
params={"sysparm_query": f"sys_id={self.user_sys_id}"},
|
|
206
|
+
)
|
|
207
|
+
laptop_record_exists = table_api_call(
|
|
208
|
+
instance=self.instance,
|
|
209
|
+
table="alm_hardware",
|
|
210
|
+
params={"sysparm_query": f"sys_id={self.laptop_sys_id}"},
|
|
211
|
+
)
|
|
212
|
+
if user_record_exists:
|
|
213
|
+
db_delete_from_table(
|
|
214
|
+
instance=self.instance,
|
|
215
|
+
table="sys_user",
|
|
216
|
+
sys_id=self.user_sys_id,
|
|
217
|
+
)
|
|
218
|
+
if laptop_record_exists:
|
|
219
|
+
db_delete_from_table(
|
|
220
|
+
instance=self.instance,
|
|
221
|
+
table="alm_hardware",
|
|
222
|
+
sys_id=self.laptop_sys_id,
|
|
223
|
+
)
|
|
224
|
+
super().teardown()
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
__TASKS__ = [GetWarrantyExpirationDateTask]
|