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.
Files changed (91) hide show
  1. browsergym/workarena/__init__.py +13 -1
  2. browsergym/workarena/api/category.py +74 -0
  3. browsergym/workarena/api/change_request.py +87 -0
  4. browsergym/workarena/api/computer_asset.py +90 -0
  5. browsergym/workarena/api/cost_center.py +19 -0
  6. browsergym/workarena/api/expense_line.py +89 -0
  7. browsergym/workarena/api/incident.py +45 -0
  8. browsergym/workarena/api/knowledge.py +29 -0
  9. browsergym/workarena/api/problem.py +90 -0
  10. browsergym/workarena/api/report.py +183 -0
  11. browsergym/workarena/api/requested_items.py +63 -0
  12. browsergym/workarena/api/user.py +11 -8
  13. browsergym/workarena/api/utils.py +47 -3
  14. browsergym/workarena/config.py +21 -1
  15. browsergym/workarena/data_files/setup_files/forms/expected_incident_form_fields.json +1 -1
  16. browsergym/workarena/data_files/setup_files/forms/expected_request_item_form_fields.json +1 -0
  17. browsergym/workarena/data_files/setup_files/knowledge/protocols.json +46 -0
  18. browsergym/workarena/data_files/setup_files/knowledge/test.html +1 -0
  19. browsergym/workarena/data_files/setup_files/lists/expected_asset_list_columns.json +2 -24
  20. browsergym/workarena/data_files/setup_files/lists/expected_change_request_list_columns.json +4 -40
  21. browsergym/workarena/data_files/setup_files/lists/expected_expense_line_list_columns.json +12 -0
  22. browsergym/workarena/data_files/setup_files/lists/expected_hardware_list_columns.json +1 -42
  23. browsergym/workarena/data_files/setup_files/lists/expected_incident_list_columns.json +2 -18
  24. browsergym/workarena/data_files/setup_files/lists/expected_problem_list_columns.json +12 -0
  25. browsergym/workarena/data_files/setup_files/lists/expected_requested_items_list_columns.json +12 -0
  26. browsergym/workarena/data_files/setup_files/lists/expected_service_catalog_list_columns.json +2 -19
  27. browsergym/workarena/data_files/setup_files/lists/expected_user_list_columns.json +3 -50
  28. browsergym/workarena/data_files/task_configs/all_menu.json +95 -95
  29. browsergym/workarena/data_files/task_configs/dashboard_retrieval_minmax_task.json +1 -1
  30. browsergym/workarena/data_files/task_configs/dashboard_retrieval_value_task.json +1 -1
  31. browsergym/workarena/data_files/task_configs/filter_service_catalog_item_list_task.json +7986 -7982
  32. browsergym/workarena/data_files/task_configs/impersonation_users.json +3 -3
  33. browsergym/workarena/data_files/task_configs/report_retrieval_minmax_task.json +1 -1
  34. browsergym/workarena/data_files/task_configs/report_retrieval_value_task.json +1 -1
  35. browsergym/workarena/human_eval/console.js +176 -0
  36. browsergym/workarena/human_eval/tool.py +366 -0
  37. browsergym/workarena/install.py +81 -20
  38. browsergym/workarena/tasks/base.py +55 -20
  39. browsergym/workarena/tasks/comp_building_block.py +4 -0
  40. browsergym/workarena/tasks/compositional/__init__.py +76 -0
  41. browsergym/workarena/tasks/compositional/base.py +364 -0
  42. browsergym/workarena/tasks/compositional/dash_do_base.py +1366 -0
  43. browsergym/workarena/tasks/compositional/dash_do_catalog.py +1127 -0
  44. browsergym/workarena/tasks/compositional/dash_do_catalog_infeasible.py +2047 -0
  45. browsergym/workarena/tasks/compositional/dash_do_create_incident.py +403 -0
  46. browsergym/workarena/tasks/compositional/dash_do_create_incident_infeasible.py +278 -0
  47. browsergym/workarena/tasks/compositional/dash_do_create_problem.py +336 -0
  48. browsergym/workarena/tasks/compositional/dash_do_create_problem_infeasible.py +235 -0
  49. browsergym/workarena/tasks/compositional/dash_do_filter.py +1600 -0
  50. browsergym/workarena/tasks/compositional/dash_do_request_item.py +1315 -0
  51. browsergym/workarena/tasks/compositional/dash_do_request_item_infeasible.py +693 -0
  52. browsergym/workarena/tasks/compositional/delete_record.py +341 -0
  53. browsergym/workarena/tasks/compositional/edit_knowledge_base.py +457 -0
  54. browsergym/workarena/tasks/compositional/expense_management.py +598 -0
  55. browsergym/workarena/tasks/compositional/filter_and_do.py +139 -0
  56. browsergym/workarena/tasks/compositional/find_and_order_item.py +345 -0
  57. browsergym/workarena/tasks/compositional/manage_change_request_schedule.py +1417 -0
  58. browsergym/workarena/tasks/compositional/mark_duplicate_problems.py +499 -0
  59. browsergym/workarena/tasks/compositional/maximize_investment_return.py +1763 -0
  60. browsergym/workarena/tasks/compositional/navigate_and_do.py +1151 -0
  61. browsergym/workarena/tasks/compositional/navigate_and_do_infeasible.py +2100 -0
  62. browsergym/workarena/tasks/compositional/offboard_user.py +207 -0
  63. browsergym/workarena/tasks/compositional/onboard_user.py +226 -0
  64. browsergym/workarena/tasks/compositional/update_task.py +145 -0
  65. browsergym/workarena/tasks/compositional/utils/curriculum.py +215 -0
  66. browsergym/workarena/tasks/compositional/utils/infeasible_configs.py +151 -0
  67. browsergym/workarena/tasks/compositional/utils/knapsack.py +192 -0
  68. browsergym/workarena/tasks/compositional/warranty_check.py +227 -0
  69. browsergym/workarena/tasks/compositional/work_assignment.py +804 -0
  70. browsergym/workarena/tasks/compositional/workload_balancing.py +396 -0
  71. browsergym/workarena/tasks/dashboard.py +188 -8
  72. browsergym/workarena/tasks/form.py +1024 -232
  73. browsergym/workarena/tasks/knowledge.py +216 -25
  74. browsergym/workarena/tasks/list.py +519 -102
  75. browsergym/workarena/tasks/mark_duplicate_problem.py +171 -0
  76. browsergym/workarena/tasks/navigation.py +55 -13
  77. browsergym/workarena/tasks/scripts/extract_all_menu_items.py +9 -2
  78. browsergym/workarena/tasks/scripts/generate_dashboard_configs.py +6 -5
  79. browsergym/workarena/tasks/scripts/service_catalog.py +2 -1
  80. browsergym/workarena/tasks/scripts/validate.py +8 -2
  81. browsergym/workarena/tasks/send_chat_message.py +90 -0
  82. browsergym/workarena/tasks/service_catalog.py +94 -26
  83. browsergym/workarena/tasks/utils/form.py +1 -4
  84. browsergym/workarena/tasks/utils/private_tasks.py +63 -0
  85. browsergym/workarena/tasks/utils/utils.py +13 -0
  86. {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/METADATA +27 -20
  87. browsergym_workarena-0.3.0.dist-info/RECORD +138 -0
  88. {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/entry_points.txt +1 -0
  89. browsergym_workarena-0.2.0.dist-info/RECORD +0 -85
  90. {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/WHEEL +0 -0
  91. {browsergym_workarena-0.2.0.dist-info → browsergym_workarena-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,336 @@
1
+ from playwright.sync_api._generated import Page
2
+ from typing import Tuple
3
+
4
+ from .dash_do_base import DashboardRetrieveIncidentAndDoTask, DashDoFinalTask
5
+
6
+ from ..base import AbstractServiceNowTask
7
+ from ..dashboard import ReportMinMaxRetrievalTask, ReportMeanMedianModeRetrievalTask
8
+
9
+ from ...api.utils import table_api_call, db_delete_from_table
10
+ from ...instance import SNowInstance
11
+
12
+ from browsergym.workarena.tasks.navigation import AllMenuTask
13
+ from browsergym.workarena.tasks.form import CreateProblemTask
14
+
15
+
16
+ class DashboardRetrieveIncidentAndCreateProblemTask(DashboardRetrieveIncidentAndDoTask):
17
+ def __init__(
18
+ self,
19
+ instance: SNowInstance = None,
20
+ seed: int = None,
21
+ fixed_config: list[AbstractServiceNowTask] = None,
22
+ level: int = 2,
23
+ question: str = None,
24
+ dashboard_class: AbstractServiceNowTask = None,
25
+ ) -> None:
26
+ """
27
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
28
+ Attributes:
29
+ -----------
30
+ task_description: str
31
+ The start of the task description to be completed.
32
+ short_description: str
33
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
34
+ """
35
+ super().__init__(
36
+ instance=instance,
37
+ seed=seed,
38
+ fixed_config=fixed_config,
39
+ level=level,
40
+ question=question,
41
+ dashboard_class=dashboard_class,
42
+ )
43
+ self.attribute_name = "assigned_to"
44
+ self.filter_than = "lesser"
45
+ self.prefix = "DCP"
46
+
47
+ def set_compositional_task(self) -> None:
48
+ agent_full_names, agent_value_sysids = self.get_agent_values(
49
+ self.attribute_name, self.filter_than
50
+ )
51
+ self.agent_value_sysids = agent_value_sysids
52
+ create_problem_subtasks = []
53
+ self.short_description = "Compulsory training for employee in probation"
54
+ for agent_full_name in agent_full_names:
55
+ problem_config = {
56
+ "fields": {
57
+ "short_description": "Problem statement",
58
+ "urgency": "Urgency",
59
+ "assigned_to": "Assigned to",
60
+ "impact": "Impact",
61
+ },
62
+ "task_fields": [
63
+ "short_description",
64
+ "urgency",
65
+ "assigned_to",
66
+ "impact",
67
+ ],
68
+ "template_record": {
69
+ "short_description": self.short_description,
70
+ "impact": "1 - High",
71
+ "urgency": "1 - High",
72
+ "assigned_to": agent_full_name,
73
+ },
74
+ }
75
+
76
+ create_problem_subtask = [
77
+ # Navigate to the incident list
78
+ AllMenuTask(
79
+ instance=self.instance,
80
+ fixed_config={
81
+ "application": "Problem",
82
+ "module": "All",
83
+ "url": "/now/nav/ui/classic/params/target/problem_list.do",
84
+ },
85
+ is_validated=False,
86
+ used_in_level_2=True,
87
+ ),
88
+ # Create a problem
89
+ CreateProblemTask(
90
+ instance=self.instance,
91
+ fixed_config=problem_config,
92
+ is_validated=False,
93
+ used_in_level_2=True,
94
+ check_record_created=False,
95
+ ),
96
+ ]
97
+ create_problem_subtasks += create_problem_subtask
98
+
99
+ self.compositional_task = create_problem_subtasks
100
+
101
+ def setup_goal(self, page: Page) -> tuple[str, dict]:
102
+ self.create_report(
103
+ user_roles=[
104
+ "itil",
105
+ "problem_admin",
106
+ "problem_manager",
107
+ "problem_coordinator",
108
+ "problem_task_analyst",
109
+ ]
110
+ )
111
+ self.set_compositional_task()
112
+ config = self.fixed_config if self.fixed_config else self._get_config()
113
+
114
+ if self.level == 3:
115
+ self.task_description = (
116
+ self.task_description
117
+ + f"\t - Please retrieve the '{self.description_mapping[self.question]}' value of the number of incidents assigned across agents. Retrieve agents that have less than or equal number of incidents assigned to them compared to this value.\n"
118
+ + f"\t For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n\n"
119
+ + f"\t - Task: For each agent that fits the above criteria, create a 'problem' with the following information (only fill these fields) and assign it to them using the 'Assigned to' field: \n"
120
+ + f"\t\t Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation'.\n"
121
+ + f"Note that you will create as many problems as there are agents matching the above criteria.\n"
122
+ + f"\t For example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n\n"
123
+ )
124
+
125
+ goal, info = super().setup_goal(page=page, config=config)
126
+
127
+ if self.level == 2:
128
+ goal = (
129
+ self.short_description
130
+ + f"\n1. Navigate to the Reports > View/Run page. \n"
131
+ + f"\n2. Given the title of the report, search for it on this page. The report shows the number of 'incidents' assigned to an 'agent'.\n"
132
+ + f"\n3. Find the agents with a number of incidents assigned less than or equal to the {self.description_mapping[self.question]} of the number of assigned incidents across agents. For example, if you were asked to find the 'mean' or 'average' for a case where there are 4 agents assigned 1,2,3,2 incidents respectively, the mean would be 2. The list of agents required for solving the following task would be all the agents that have less than or equal to 2 assigned incidents.\n"
133
+ + f"\n4. Navigate to All > Problems. \n"
134
+ + f"\n5. You have to create new 'problems' from this page for all the agents based on the above criteria. Only fill the following fields when creating a new problem:- Impact: '1 - High', Urgency: '1 - High', Problem statement: 'Compulsory training for employee in probation' and 'assign' them to each agent.\n\n"
135
+ + f"Note that you will create as many problems as there are agents matching the above criteria."
136
+ + "\nFor example, consider the above case and say you have 3 agents with less than or equal to 2 incidents assigned to them in the chart. You will be creating '3' problems here, one assigned to each agent. \n"
137
+ )
138
+
139
+ return goal, info
140
+
141
+ def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
142
+ fixed_template_record = {
143
+ "short_description": "Compulsory training for employee in probation",
144
+ "impact": "1",
145
+ "urgency": "1",
146
+ }
147
+ for agent_sysid in self.agent_value_sysids:
148
+ created_problem_response = table_api_call(
149
+ instance=self.instance,
150
+ table="problem",
151
+ params={
152
+ "sysparm_query": f"assigned_to={agent_sysid}^short_description={self.short_description}",
153
+ },
154
+ method="GET",
155
+ )["result"]
156
+ if len(created_problem_response) == 0:
157
+ return (
158
+ 0,
159
+ False,
160
+ "",
161
+ {
162
+ "message": f"No problem created for agent {self.agents[agent_sysid]['user_name']}."
163
+ },
164
+ )
165
+ elif len(created_problem_response) > 1:
166
+ return (
167
+ 0,
168
+ False,
169
+ "",
170
+ {
171
+ "message": f"Multiple problems created for agent {self.agents[agent_sysid]['user_name']}."
172
+ },
173
+ )
174
+ created_problem_response = created_problem_response[0]
175
+ for key, value in fixed_template_record.items():
176
+ if str(created_problem_response[key]).lower() != str(value).lower():
177
+ return (
178
+ 0,
179
+ False,
180
+ "",
181
+ {
182
+ "message": f"Problem for agent {self.agents[agent_sysid]['user_name']} assigned incorrect value to field {key}."
183
+ },
184
+ )
185
+ reward, done, message, info = super().validate(page, chat_messages)
186
+ return reward, done, message, info
187
+
188
+ def teardown(self) -> None:
189
+ for agent_sysid in self.agent_sysids:
190
+ created_problem_response = table_api_call(
191
+ instance=self.instance,
192
+ table="problem",
193
+ params={
194
+ "sysparm_query": f"assigned_to={agent_sysid}",
195
+ },
196
+ method="GET",
197
+ )["result"]
198
+ for problem in created_problem_response:
199
+ db_delete_from_table(
200
+ instance=self.instance,
201
+ table="problem",
202
+ sys_id=problem["sys_id"],
203
+ )
204
+ return super().teardown()
205
+
206
+
207
+ class DashboardRetrieveIncidentAndMinCreateProblemTask(
208
+ DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
209
+ ):
210
+ def __init__(
211
+ self,
212
+ instance: SNowInstance = None,
213
+ seed: int = None,
214
+ fixed_config: list[AbstractServiceNowTask] = None,
215
+ level: int = 2,
216
+ ) -> None:
217
+ """
218
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
219
+ Attributes:
220
+ -----------
221
+ task_description: str
222
+ The start of the task description to be completed.
223
+ short_description: str
224
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
225
+ """
226
+ super().__init__(
227
+ instance=instance,
228
+ seed=seed,
229
+ fixed_config=fixed_config,
230
+ level=level,
231
+ question="min",
232
+ dashboard_class=ReportMinMaxRetrievalTask,
233
+ )
234
+
235
+
236
+ class DashboardRetrieveIncidentAndMeanCreateProblemTask(
237
+ DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
238
+ ):
239
+ def __init__(
240
+ self,
241
+ instance: SNowInstance = None,
242
+ seed: int = None,
243
+ fixed_config: list[AbstractServiceNowTask] = None,
244
+ level: int = 2,
245
+ ) -> None:
246
+ """
247
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
248
+ Attributes:
249
+ -----------
250
+ task_description: str
251
+ The start of the task description to be completed.
252
+ short_description: str
253
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
254
+ """
255
+ super().__init__(
256
+ instance=instance,
257
+ seed=seed,
258
+ fixed_config=fixed_config,
259
+ level=level,
260
+ question="mean",
261
+ dashboard_class=ReportMeanMedianModeRetrievalTask,
262
+ )
263
+
264
+
265
+ class DashboardRetrieveIncidentAndMedianCreateProblemTask(
266
+ DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
267
+ ):
268
+ def __init__(
269
+ self,
270
+ instance: SNowInstance = None,
271
+ seed: int = None,
272
+ fixed_config: list[AbstractServiceNowTask] = None,
273
+ level: int = 2,
274
+ ) -> None:
275
+ """
276
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
277
+ Attributes:
278
+ -----------
279
+ task_description: str
280
+ The start of the task description to be completed.
281
+ short_description: str
282
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
283
+ """
284
+ super().__init__(
285
+ instance=instance,
286
+ seed=seed,
287
+ fixed_config=fixed_config,
288
+ level=level,
289
+ question="median",
290
+ dashboard_class=ReportMeanMedianModeRetrievalTask,
291
+ )
292
+
293
+
294
+ class DashboardRetrieveIncidentAndModeCreateProblemTask(
295
+ DashboardRetrieveIncidentAndCreateProblemTask, DashDoFinalTask
296
+ ):
297
+ def __init__(
298
+ self,
299
+ instance: SNowInstance = None,
300
+ seed: int = None,
301
+ fixed_config: list[AbstractServiceNowTask] = None,
302
+ level: int = 2,
303
+ ) -> None:
304
+ """
305
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
306
+ Attributes:
307
+ -----------
308
+ task_description: str
309
+ The start of the task description to be completed.
310
+ short_description: str
311
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
312
+ """
313
+ super().__init__(
314
+ instance=instance,
315
+ seed=seed,
316
+ fixed_config=fixed_config,
317
+ level=level,
318
+ question="mode",
319
+ dashboard_class=ReportMeanMedianModeRetrievalTask,
320
+ )
321
+
322
+
323
+ local_vars = locals().copy()
324
+
325
+ __TASKS__ = [
326
+ var
327
+ for var in local_vars.values()
328
+ if isinstance(var, type) and issubclass(var, DashDoFinalTask) and var is not DashDoFinalTask
329
+ ]
330
+
331
+ DASH_AND_CREATE_PROBLEM = [DashboardRetrieveIncidentAndMinCreateProblemTask]
332
+ DASH_COMPUTE_AND_CREATE_PROBLEM = [
333
+ DashboardRetrieveIncidentAndMeanCreateProblemTask,
334
+ DashboardRetrieveIncidentAndMedianCreateProblemTask,
335
+ DashboardRetrieveIncidentAndModeCreateProblemTask,
336
+ ]
@@ -0,0 +1,235 @@
1
+ from playwright.sync_api._generated import Page
2
+ from typing import Tuple
3
+
4
+ from .dash_do_base import DashboardRetrieveIncidentAndDoInfeasibleTask, DashDoFinalTask
5
+ from .utils.infeasible_configs import get_infeasible_form_config
6
+
7
+ from ..base import AbstractServiceNowTask
8
+ from ..dashboard import ReportMinMaxRetrievalTask
9
+
10
+ from ...api.utils import table_api_call, db_delete_from_table
11
+ from ...instance import SNowInstance
12
+
13
+ from browsergym.workarena.tasks.navigation import AllMenuTask
14
+ from browsergym.workarena.tasks.form import CreateProblemTask
15
+
16
+
17
+ class DashboardRetrieveIncidentAndCreateProblemInfeasibleTask(
18
+ DashboardRetrieveIncidentAndDoInfeasibleTask
19
+ ):
20
+ def __init__(
21
+ self,
22
+ instance: SNowInstance = None,
23
+ seed: int = None,
24
+ fixed_config: list[AbstractServiceNowTask] = None,
25
+ level: int = 2,
26
+ question: str = None,
27
+ dashboard_class: AbstractServiceNowTask = None,
28
+ provide_reason: bool = None,
29
+ ) -> None:
30
+ """
31
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
32
+ Attributes:
33
+ -----------
34
+ task_description: str
35
+ The start of the task description to be completed.
36
+ short_description: str
37
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
38
+ """
39
+ super().__init__(
40
+ instance=instance,
41
+ seed=seed,
42
+ fixed_config=fixed_config,
43
+ level=level,
44
+ question=question,
45
+ dashboard_class=dashboard_class,
46
+ function=get_infeasible_form_config,
47
+ provide_reason=provide_reason,
48
+ )
49
+ self.task_description = ""
50
+ self.short_description = "Create a problem for the worst performing employee from the list."
51
+ self.attribute_name = "assigned_to"
52
+ self.filter_than = "lesser"
53
+ self.prefix = "ICP"
54
+
55
+ def set_compositional_task(self) -> None:
56
+ agent_full_names, agent_value_sysids = self.get_agent_values(
57
+ self.attribute_name, self.filter_than
58
+ )
59
+ self.agent_value_sysids = agent_value_sysids
60
+ create_problem_subtasks = []
61
+ for agent_full_name in agent_full_names:
62
+ problem_config = {
63
+ "fields": {
64
+ "short_description": "Problem statement",
65
+ "description": "Description",
66
+ "urgency": "Urgency",
67
+ "assigned_to": "Assigned to",
68
+ "impact": "Impact",
69
+ },
70
+ "task_fields": [
71
+ "short_description",
72
+ "description",
73
+ "urgency",
74
+ "assigned_to",
75
+ "impact",
76
+ ],
77
+ "template_record": {
78
+ "description": "Compulsory training for employee in probation",
79
+ "short_description": "Compulsory training for employee in probation",
80
+ "impact": "1 - High",
81
+ "urgency": "1 - High",
82
+ "assigned_to": agent_full_name,
83
+ },
84
+ "infeasible_task_fields": ["short_description", "description", "urgency", "impact"],
85
+ }
86
+ problem_config, self.infeasible_reasons = self.function(
87
+ config=problem_config, random=self.random
88
+ )
89
+
90
+ create_problem_subtask = [
91
+ # Navigate to the incident list
92
+ AllMenuTask(
93
+ instance=self.instance,
94
+ fixed_config={
95
+ "application": "Problem",
96
+ "module": "All",
97
+ "url": "/now/nav/ui/classic/params/target/problem_list.do",
98
+ },
99
+ is_validated=False,
100
+ used_in_level_2=True,
101
+ ),
102
+ # Create a problem
103
+ CreateProblemTask(
104
+ instance=self.instance,
105
+ fixed_config=problem_config,
106
+ is_validated=False,
107
+ used_in_level_2=True,
108
+ check_record_created=False,
109
+ ),
110
+ ]
111
+ create_problem_subtasks += create_problem_subtask
112
+
113
+ self.compositional_task = create_problem_subtasks
114
+
115
+ def setup_goal(self, page: Page) -> tuple[str, dict]:
116
+ self.create_report(
117
+ user_roles=[
118
+ "itil",
119
+ "problem_admin",
120
+ "problem_manager",
121
+ "problem_coordinator",
122
+ "problem_task_analyst",
123
+ ]
124
+ )
125
+ self.set_compositional_task()
126
+ config = self.fixed_config if self.fixed_config else self._get_config()
127
+ if self.level == 3:
128
+ self.task_description = (
129
+ self.task_description
130
+ + f"Value to retrieve: {self.description_mapping[self.question]} of all the incidents. Comparator: Less than or equal to the value.\n"
131
+ + f"Task: Create problems with the following information: \n"
132
+ + f"Category: 'Inquiry / Help', Impact: '1 - High', Urgency: '1 - High', Short description: 'Compulsory training for employee in probation'.\n"
133
+ + f"Assign the problems you create to the agents mentioned above."
134
+ )
135
+
136
+ goal, info = super().setup_goal(page=page, config=config)
137
+
138
+ if self.level == 2:
139
+ goal = (
140
+ self.task_description
141
+ + f"\n1. Navigate to the CMDB reports and look for the report with the mentioned hashtag. \n"
142
+ + f"\n2. Find the agents with number of incidents less than or equal to the {self.description_mapping[self.question]} of the incidents assigned to every one. \n"
143
+ + f"\n3. Navigate to All > Problems. \n"
144
+ + f"\n4. Create new problems with the following field values:- Category: 'Inquiry / Help', Impact: '1 - High', Urgency: '1 - High', Short description: 'Compulsory training for employee in probation' and assign them to each of the agents."
145
+ + "\nYou will create as many problems as there are agents.\n"
146
+ )
147
+
148
+ return goal, info
149
+
150
+ def teardown(self) -> None:
151
+ for agent_sysid in self.agent_sysids:
152
+ created_problem_response = table_api_call(
153
+ instance=self.instance,
154
+ table="problem",
155
+ params={
156
+ "sysparm_query": f"assigned_to={agent_sysid}",
157
+ },
158
+ method="GET",
159
+ )["result"]
160
+ for problem in created_problem_response:
161
+ db_delete_from_table(
162
+ instance=self.instance,
163
+ table="problem",
164
+ sys_id=problem["sys_id"],
165
+ )
166
+ return super().teardown()
167
+
168
+
169
+ class DashboardRetrieveIncidentAndMinCreateProblemInfeasibleWithReasonTask(
170
+ DashboardRetrieveIncidentAndCreateProblemInfeasibleTask, DashDoFinalTask
171
+ ):
172
+ def __init__(
173
+ self,
174
+ instance: SNowInstance = None,
175
+ seed: int = None,
176
+ fixed_config: list[AbstractServiceNowTask] = None,
177
+ level: int = 2,
178
+ ) -> None:
179
+ """
180
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
181
+ Attributes:
182
+ -----------
183
+ task_description: str
184
+ The start of the task description to be completed.
185
+ short_description: str
186
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
187
+ """
188
+ super().__init__(
189
+ instance=instance,
190
+ seed=seed,
191
+ fixed_config=fixed_config,
192
+ level=level,
193
+ question="min",
194
+ dashboard_class=ReportMinMaxRetrievalTask,
195
+ provide_reason=True,
196
+ )
197
+
198
+
199
+ class DashboardRetrieveIncidentAndMinCreateProblemInfeasibleTask(
200
+ DashboardRetrieveIncidentAndCreateProblemInfeasibleTask, DashDoFinalTask
201
+ ):
202
+ def __init__(
203
+ self,
204
+ instance: SNowInstance = None,
205
+ seed: int = None,
206
+ fixed_config: list[AbstractServiceNowTask] = None,
207
+ level: int = 2,
208
+ ) -> None:
209
+ """
210
+ Retrieve the worst performing employee and create a problem to assign them a probation course.
211
+ Attributes:
212
+ -----------
213
+ task_description: str
214
+ The start of the task description to be completed.
215
+ short_description: str
216
+ A short description of the task to be completed. "Create a problem for the worst performing employee from the list"
217
+ """
218
+ super().__init__(
219
+ instance=instance,
220
+ seed=seed,
221
+ fixed_config=fixed_config,
222
+ level=level,
223
+ question="min",
224
+ dashboard_class=ReportMinMaxRetrievalTask,
225
+ provide_reason=False,
226
+ )
227
+
228
+
229
+ local_vars = locals().copy()
230
+
231
+ __TASKS__ = [
232
+ var
233
+ for var in local_vars.values()
234
+ if isinstance(var, type) and issubclass(var, DashDoFinalTask) and var is not DashDoFinalTask
235
+ ]