browsergym-workarena 0.2.1__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 +1 -1
  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 +1 -1
  32. browsergym/workarena/data_files/task_configs/impersonation_users.json +1 -1
  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.1.dist-info → browsergym_workarena-0.3.0.dist-info}/METADATA +19 -18
  87. browsergym_workarena-0.3.0.dist-info/RECORD +138 -0
  88. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.0.dist-info}/entry_points.txt +1 -0
  89. browsergym_workarena-0.2.1.dist-info/RECORD +0 -85
  90. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.0.dist-info}/WHEEL +0 -0
  91. {browsergym_workarena-0.2.1.dist-info → browsergym_workarena-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,598 @@
1
+ import re
2
+
3
+ from datetime import timedelta
4
+ from faker import Faker
5
+ from typing import List, Tuple
6
+
7
+ fake = Faker()
8
+
9
+ from playwright.sync_api._generated import Page
10
+
11
+ from .base import HumanEvalTask
12
+ from .delete_record import DeleteExpenseLineExpenseManagementTask
13
+ from .filter_and_do import FilterAndDoTask
14
+
15
+ from ..base import AbstractServiceNowTask
16
+
17
+ from ...api.change_request import create_change_request
18
+ from ...api.expense_line import create_expense_line
19
+ from ...api.utils import table_api_call, db_delete_from_table
20
+ from ...config import (
21
+ # Expected columns for the different lists
22
+ EXPECTED_EXPENSE_LINE_COLUMNS_PATH,
23
+ )
24
+ from ...instance import SNowInstance
25
+
26
+
27
+ class ExpenseManagementTask(FilterAndDoTask):
28
+ """Task to manage expenses.
29
+ Args:
30
+
31
+ num_duplicates: int
32
+ The number of duplicate expenses to create
33
+ extra_expenses: int
34
+ The number of extra expenses to create (total expenses will be num_duplicates + extra_expenses)
35
+ goal_type: str
36
+ The type of goal to generate. Choice of "base", "date", "amount", "any".
37
+ - "base": one expense is linked to a change request, others are not and are expected to be deleted
38
+ - "date": none of the expenses are linked to change requests; the oldest one is expeted to be deleted
39
+ - "amount": none of the expenses are linked to change requests and they are all created on the same date;
40
+ the most expensive one is expeted to be deleted
41
+ - "any": any of the expenses can be deleted
42
+ """
43
+
44
+ min_allowed_amount = 100
45
+ max_allowed_amount = 10000
46
+
47
+ def __init__(
48
+ self,
49
+ seed: int,
50
+ instance: SNowInstance = None,
51
+ fixed_config: list[AbstractServiceNowTask] = None,
52
+ num_duplicates: int = 2,
53
+ extra_expenses: int = 2,
54
+ goal_type: str = "base",
55
+ level: int = 2,
56
+ ) -> None:
57
+ super().__init__(
58
+ seed=seed,
59
+ instance=instance,
60
+ fixed_config=fixed_config,
61
+ navigation_config={
62
+ "module": "Expense Lines",
63
+ "application": "Cost",
64
+ },
65
+ level=level,
66
+ protocol_name="Managing Your Existing Expenses",
67
+ )
68
+ self.num_duplicates = num_duplicates
69
+ self.extra_expenses = extra_expenses
70
+ self.total_expenses = num_duplicates + extra_expenses
71
+ self.goal_type = goal_type
72
+ self.change_request_sysids = []
73
+
74
+ # mappings between number -> (is_duplicate, sys_id)
75
+ self.expense_lines = {}
76
+ self.expense_to_keep_number = None # The number of the expense that will be kept; i.e. not deleted by the cheat/agent if successful
77
+
78
+ self.expense_hashtag = "#SERIES-" + self.unique_id[:10]
79
+ self.short_description = f"Managing Your Existing Expenses"
80
+ self.task_description = f'Referring to company protocol "{self.protocol_name}" (located in the "Company Protocols" knowledge base) manage your expenses with short description containing hashtag {self.expense_hashtag}. '
81
+ self.tasks = []
82
+
83
+ def _setup_list(self) -> None:
84
+ """The setup might be a bit complex on a first read. To understand it better, refer to the protocol for this task."""
85
+ self.filter_config = {
86
+ "list_url": "/now/nav/ui/classic/params/target/fm_expense_line_list.do",
87
+ "expected_fields_path": EXPECTED_EXPENSE_LINE_COLUMNS_PATH,
88
+ "filter_columns": [
89
+ "short_description",
90
+ ],
91
+ "filter_kind": "AND",
92
+ "filter_operators": ["contains"],
93
+ "filter_values": [
94
+ f"{self.expense_hashtag}",
95
+ ],
96
+ }
97
+
98
+ # Short description to use for duplicate expenses
99
+ duplicate_short_description = f"{fake.sentence(4)}"
100
+
101
+ # Set the default amount and date in case uniform_amount and uniform_date are True
102
+ amount = round(self.random.uniform(self.min_allowed_amount, self.max_allowed_amount), 2)
103
+ start_date = fake.date_this_decade(before_today=True, after_today=False)
104
+ date = start_date
105
+
106
+ most_expensive_amount = float("-inf")
107
+
108
+ most_expensive_duplicate_expense_number = None
109
+ oldest_duplicate_expense_number = None
110
+ only_expense_with_change_request = None
111
+ # id of expenses will be this id + their order in the creation
112
+ unique_id = str(int(self.unique_id.replace("-", ""), 16))[:10]
113
+ for i in range(self.total_expenses):
114
+ expense_number = f"EXP-{i}{unique_id }"
115
+ is_duplicate = i < self.num_duplicates
116
+ # set task sys_id to empty string if no change request is created
117
+ task_sys_id = ""
118
+
119
+ # Set a random date between start_date and today
120
+ if self.goal_type in ["base", "date"] and i > 0:
121
+ date = str(
122
+ fake.date_between(start_date=start_date + timedelta(1), end_date="today")
123
+ )
124
+ else:
125
+ date = start_date
126
+ if i == 0:
127
+ oldest_duplicate_expense_number = expense_number
128
+
129
+ # In the 'any' case, there are no change requests, all dates are the same and the prices are the same
130
+ if self.goal_type != "any":
131
+ amount = round(
132
+ self.random.uniform(self.min_allowed_amount, self.max_allowed_amount), 2
133
+ )
134
+ if is_duplicate and amount > most_expensive_amount:
135
+ most_expensive_amount = amount
136
+ most_expensive_duplicate_expense_number = expense_number
137
+
138
+ # Create a change request for the base case
139
+ if self.goal_type == "base" and i == 0:
140
+ task_sys_id, _ = create_change_request(
141
+ instance=self.instance,
142
+ user_sys_id=self._base_user_sysid,
143
+ hashtag=self.expense_hashtag,
144
+ impact=2,
145
+ risk=2,
146
+ random=self.random,
147
+ )
148
+ self.change_request_sysids.append(task_sys_id)
149
+ only_expense_with_change_request = expense_number
150
+
151
+ # Set the short description for the duplicate expenses; otherwise pass None, which will generate a random one
152
+ short_description = duplicate_short_description if i < self.num_duplicates else None
153
+
154
+ expense_sys_id, _ = create_expense_line(
155
+ instance=self.instance,
156
+ amount=amount,
157
+ number=expense_number,
158
+ date=str(date),
159
+ short_description=short_description,
160
+ expense_hashtag=self.expense_hashtag,
161
+ user_sys_id=self._base_user_sysid,
162
+ task_sys_id=task_sys_id,
163
+ )
164
+ self.expense_lines[expense_number] = (is_duplicate, expense_sys_id)
165
+
166
+ # keep the number of the expense that will be linked to the change request
167
+ if self.goal_type == "base":
168
+ self.expense_to_keep_number = only_expense_with_change_request
169
+ # keep the oldest expense
170
+ elif self.goal_type == "date":
171
+ self.expense_to_keep_number = oldest_duplicate_expense_number
172
+ elif self.goal_type == "amount":
173
+ self.expense_to_keep_number = most_expensive_duplicate_expense_number
174
+ else:
175
+ self.expense_to_keep_number = oldest_duplicate_expense_number
176
+
177
+ # As the task description redundant, we keep only the first one and skip the rest
178
+ skip_description = False
179
+ # Create the tasks to delete the extra expenses
180
+ for expense_number, (is_duplicate, expense_sys_id) in self.expense_lines.items():
181
+ if expense_number == self.expense_to_keep_number or not is_duplicate:
182
+ continue
183
+ self.tasks.append(
184
+ DeleteExpenseLineExpenseManagementTask(
185
+ instance=self.instance,
186
+ fixed_config={
187
+ "field_name": "number",
188
+ "field_value": f"{expense_number}",
189
+ },
190
+ is_validated=False,
191
+ used_in_level_2=True,
192
+ record_sys_id=expense_sys_id,
193
+ record_number=expense_number,
194
+ level=self.level,
195
+ skip_description=skip_description,
196
+ goal_type=self.goal_type,
197
+ )
198
+ )
199
+ skip_description = True
200
+
201
+ def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
202
+ expenses = table_api_call(
203
+ instance=self.instance,
204
+ table="fm_expense_line",
205
+ params={
206
+ "sysparm_query": f"short_descriptionLIKE{self.expense_hashtag}",
207
+ "sysparm_fields": "number,amount,sys_id",
208
+ },
209
+ )["result"]
210
+ # There should remain only one duplicate expense after the task is completed and the extra expenses should reamin
211
+ target_num_expenses = self.extra_expenses + 1
212
+ # Check that only one of the duplicated expenses exists and it is the right one
213
+ if len(expenses) != target_num_expenses:
214
+ return (
215
+ 0,
216
+ False,
217
+ "",
218
+ {"message": "Wrong number of expenses."},
219
+ )
220
+
221
+ existing_expense_numbers = {expense["number"] for expense in expenses}
222
+ for expense_number, (is_duplicate, _) in self.expense_lines.items():
223
+ # Check that only one of the duplicated expenses exists and it is the right one
224
+ if expense_number == self.expense_to_keep_number:
225
+ if expense_number not in existing_expense_numbers:
226
+ return (
227
+ 0,
228
+ False,
229
+ "",
230
+ {"message": "The expected duplicate to keep is missing."},
231
+ )
232
+
233
+ # Check that other duplicates have been deleted
234
+ elif is_duplicate and expense_number in existing_expense_numbers:
235
+ return (
236
+ 0,
237
+ False,
238
+ "",
239
+ {"message": "An unexpected duplicate is present."},
240
+ )
241
+ # Check that the extra expenses have not been deleted
242
+ elif not is_duplicate and expense_number not in existing_expense_numbers:
243
+ return (
244
+ 0,
245
+ False,
246
+ "",
247
+ {"message": "An extra expense has been deleted."},
248
+ )
249
+
250
+ # Validate final_l3 tasks
251
+ reward, done, message, info = super().validate(page, chat_messages)
252
+ return reward, done, message, info
253
+
254
+ def teardown(self) -> None:
255
+ for _, expense_sys_id in self.expense_lines.values():
256
+ record_exists = table_api_call(
257
+ instance=self.instance,
258
+ table="fm_expense_line",
259
+ params={"sysparm_query": f"sys_id={expense_sys_id}"},
260
+ )["result"]
261
+ if not record_exists:
262
+ continue
263
+ db_delete_from_table(
264
+ instance=self.instance,
265
+ table="fm_expense_line",
266
+ sys_id=expense_sys_id,
267
+ )
268
+ for change_request_sys_id in self.change_request_sysids:
269
+ record_exists = table_api_call(
270
+ instance=self.instance,
271
+ table="change_request",
272
+ params={"sysparm_query": f"sys_id={change_request_sys_id}"},
273
+ )["result"]
274
+ if not record_exists:
275
+ continue
276
+ db_delete_from_table(
277
+ instance=self.instance,
278
+ table="change_request",
279
+ sys_id=change_request_sys_id,
280
+ )
281
+ super().teardown()
282
+
283
+
284
+ class BasicExpenseManagementSmallTask(ExpenseManagementTask, HumanEvalTask):
285
+ def __init__(
286
+ self,
287
+ seed: int,
288
+ instance: SNowInstance = None,
289
+ fixed_config: List[AbstractServiceNowTask] = None,
290
+ num_duplicates: int = 2,
291
+ extra_expenses: int = 2,
292
+ level: int = 2,
293
+ ) -> None:
294
+ super().__init__(
295
+ seed=seed,
296
+ instance=instance,
297
+ fixed_config=fixed_config,
298
+ num_duplicates=num_duplicates,
299
+ extra_expenses=extra_expenses,
300
+ goal_type="base",
301
+ level=level,
302
+ )
303
+
304
+
305
+ class DateBasedExpenseManagementSmallTask(ExpenseManagementTask, HumanEvalTask):
306
+ def __init__(
307
+ self,
308
+ seed: int,
309
+ instance: SNowInstance = None,
310
+ fixed_config: List[AbstractServiceNowTask] = None,
311
+ num_duplicates: int = 2,
312
+ extra_expenses: int = 2,
313
+ level: int = 2,
314
+ ) -> None:
315
+ super().__init__(
316
+ seed=seed,
317
+ instance=instance,
318
+ fixed_config=fixed_config,
319
+ num_duplicates=num_duplicates,
320
+ extra_expenses=extra_expenses,
321
+ goal_type="date",
322
+ level=level,
323
+ )
324
+
325
+
326
+ class AmountBasedExpenseManagementSmallTask(ExpenseManagementTask, HumanEvalTask):
327
+ def __init__(
328
+ self,
329
+ seed: int,
330
+ instance: SNowInstance = None,
331
+ fixed_config: List[AbstractServiceNowTask] = None,
332
+ num_duplicates: int = 2,
333
+ extra_expenses: int = 2,
334
+ level: int = 2,
335
+ ) -> None:
336
+ super().__init__(
337
+ seed=seed,
338
+ instance=instance,
339
+ fixed_config=fixed_config,
340
+ num_duplicates=num_duplicates,
341
+ extra_expenses=extra_expenses,
342
+ goal_type="amount",
343
+ level=level,
344
+ )
345
+
346
+
347
+ class EasyExpenseManagementTask(ExpenseManagementTask):
348
+ def __init__(
349
+ self,
350
+ seed: int,
351
+ instance: SNowInstance = None,
352
+ fixed_config: List[AbstractServiceNowTask] = None,
353
+ num_duplicates: int = 2,
354
+ extra_expenses: int = 2,
355
+ level: int = 2,
356
+ ) -> None:
357
+ super().__init__(
358
+ seed=seed,
359
+ instance=instance,
360
+ fixed_config=fixed_config,
361
+ num_duplicates=num_duplicates,
362
+ extra_expenses=extra_expenses,
363
+ goal_type="any",
364
+ level=level,
365
+ )
366
+
367
+ def validate(self, page: Page, chat_messages: list[str]) -> Tuple[float, bool, str, dict]:
368
+ expenses = table_api_call(
369
+ instance=self.instance,
370
+ table="fm_expense_line",
371
+ params={
372
+ "sysparm_query": f"short_descriptionLIKE{self.expense_hashtag}",
373
+ "sysparm_fields": "number,amount,sys_id",
374
+ },
375
+ )["result"]
376
+ # There should remain only one expense after the task is completed and the extra expenses should reamin
377
+ target_num_expenses = self.extra_expenses + 1
378
+ # Check that only one of the duplicated expenses exists and it is the right one
379
+ if len(expenses) != target_num_expenses:
380
+ return (
381
+ 0,
382
+ False,
383
+ "",
384
+ {"message": "Wrong number of expenses."},
385
+ )
386
+
387
+ existing_expense_numbers = {expense["number"] for expense in expenses}
388
+ for expense_number, (is_duplicate, _) in self.expense_lines.items():
389
+ if not is_duplicate and expense_number not in existing_expense_numbers:
390
+ return (
391
+ 0,
392
+ False,
393
+ "",
394
+ {"message": "An extra expense has been deleted."},
395
+ )
396
+
397
+ # Validate final_l3 tasks
398
+ reward, done, message, info = FilterAndDoTask.validate(self, page, chat_messages)
399
+ return reward, done, message, info
400
+
401
+
402
+ class EasyExpenseManagementSmallTask(EasyExpenseManagementTask, HumanEvalTask):
403
+ def __init__(
404
+ self,
405
+ seed: int,
406
+ instance: SNowInstance = None,
407
+ fixed_config: List[AbstractServiceNowTask] = None,
408
+ num_duplicates: int = 2,
409
+ extra_expenses: int = 2,
410
+ level: int = 2,
411
+ ) -> None:
412
+ super().__init__(
413
+ seed=seed,
414
+ instance=instance,
415
+ fixed_config=fixed_config,
416
+ num_duplicates=num_duplicates,
417
+ extra_expenses=extra_expenses,
418
+ level=level,
419
+ )
420
+
421
+
422
+ class BasicExpenseManagementMediumTask(ExpenseManagementTask):
423
+ def __init__(
424
+ self,
425
+ seed: int,
426
+ instance: SNowInstance = None,
427
+ fixed_config: List[AbstractServiceNowTask] = None,
428
+ num_duplicates: int = 4,
429
+ extra_expenses: int = 4,
430
+ level: int = 2,
431
+ ) -> None:
432
+ super().__init__(
433
+ seed=seed,
434
+ instance=instance,
435
+ fixed_config=fixed_config,
436
+ num_duplicates=num_duplicates,
437
+ extra_expenses=extra_expenses,
438
+ goal_type="base",
439
+ level=level,
440
+ )
441
+
442
+
443
+ class DateBasedExpenseManagementMediumTask(ExpenseManagementTask):
444
+ def __init__(
445
+ self,
446
+ seed: int,
447
+ instance: SNowInstance = None,
448
+ fixed_config: List[AbstractServiceNowTask] = None,
449
+ num_duplicates: int = 4,
450
+ extra_expenses: int = 4,
451
+ level: int = 2,
452
+ ) -> None:
453
+ super().__init__(
454
+ seed=seed,
455
+ instance=instance,
456
+ fixed_config=fixed_config,
457
+ num_duplicates=num_duplicates,
458
+ extra_expenses=extra_expenses,
459
+ goal_type="date",
460
+ level=level,
461
+ )
462
+
463
+
464
+ class AmountBasedExpenseManagementMediumTask(ExpenseManagementTask):
465
+ def __init__(
466
+ self,
467
+ seed: int,
468
+ instance: SNowInstance = None,
469
+ fixed_config: List[AbstractServiceNowTask] = None,
470
+ num_duplicates: int = 4,
471
+ extra_expenses: int = 4,
472
+ level: int = 2,
473
+ ) -> None:
474
+ super().__init__(
475
+ seed=seed,
476
+ instance=instance,
477
+ fixed_config=fixed_config,
478
+ num_duplicates=num_duplicates,
479
+ extra_expenses=extra_expenses,
480
+ goal_type="amount",
481
+ level=level,
482
+ )
483
+
484
+
485
+ class EasyExpenseManagementMediumTask(EasyExpenseManagementTask):
486
+ def __init__(
487
+ self,
488
+ seed: int,
489
+ instance: SNowInstance = None,
490
+ fixed_config: List[AbstractServiceNowTask] = None,
491
+ num_duplicates: int = 4,
492
+ extra_expenses: int = 4,
493
+ level: int = 2,
494
+ ) -> None:
495
+ super().__init__(
496
+ seed=seed,
497
+ instance=instance,
498
+ fixed_config=fixed_config,
499
+ num_duplicates=num_duplicates,
500
+ extra_expenses=extra_expenses,
501
+ level=level,
502
+ )
503
+
504
+
505
+ class BasicExpenseManagementLargeTask(ExpenseManagementTask):
506
+ def __init__(
507
+ self,
508
+ seed: int,
509
+ instance: SNowInstance = None,
510
+ fixed_config: List[AbstractServiceNowTask] = None,
511
+ num_duplicates: int = 6,
512
+ extra_expenses: int = 6,
513
+ level: int = 2,
514
+ ) -> None:
515
+ super().__init__(
516
+ seed=seed,
517
+ instance=instance,
518
+ fixed_config=fixed_config,
519
+ num_duplicates=num_duplicates,
520
+ extra_expenses=extra_expenses,
521
+ goal_type="base",
522
+ level=level,
523
+ )
524
+
525
+
526
+ class DateBasedExpenseManagementLargeTask(ExpenseManagementTask):
527
+ def __init__(
528
+ self,
529
+ seed: int,
530
+ instance: SNowInstance = None,
531
+ fixed_config: List[AbstractServiceNowTask] = None,
532
+ num_duplicates: int = 6,
533
+ extra_expenses: int = 6,
534
+ level: int = 2,
535
+ ) -> None:
536
+ super().__init__(
537
+ seed=seed,
538
+ instance=instance,
539
+ fixed_config=fixed_config,
540
+ num_duplicates=num_duplicates,
541
+ extra_expenses=extra_expenses,
542
+ goal_type="date",
543
+ level=level,
544
+ )
545
+
546
+
547
+ class AmountBasedExpenseManagementLargeTask(ExpenseManagementTask):
548
+ def __init__(
549
+ self,
550
+ seed: int,
551
+ instance: SNowInstance = None,
552
+ fixed_config: List[AbstractServiceNowTask] = None,
553
+ num_duplicates: int = 6,
554
+ extra_expenses: int = 6,
555
+ level: int = 2,
556
+ ) -> None:
557
+ super().__init__(
558
+ seed=seed,
559
+ instance=instance,
560
+ fixed_config=fixed_config,
561
+ num_duplicates=num_duplicates,
562
+ extra_expenses=extra_expenses,
563
+ goal_type="amount",
564
+ level=level,
565
+ )
566
+
567
+
568
+ class EasyExpenseManagementLargeTask(EasyExpenseManagementTask):
569
+ def __init__(
570
+ self,
571
+ seed: int,
572
+ instance: SNowInstance = None,
573
+ fixed_config: List[AbstractServiceNowTask] = None,
574
+ num_duplicates: int = 6,
575
+ extra_expenses: int = 6,
576
+ level: int = 2,
577
+ ) -> None:
578
+ super().__init__(
579
+ seed=seed,
580
+ instance=instance,
581
+ fixed_config=fixed_config,
582
+ num_duplicates=num_duplicates,
583
+ extra_expenses=extra_expenses,
584
+ level=level,
585
+ )
586
+
587
+
588
+ local_vars = locals().copy()
589
+
590
+ __TASKS__ = [
591
+ var
592
+ for var in local_vars.values()
593
+ if isinstance(var, type)
594
+ and issubclass(var, FilterAndDoTask)
595
+ and var is not FilterAndDoTask
596
+ and var is not ExpenseManagementTask
597
+ and var is not EasyExpenseManagementTask
598
+ ]