clerk-sdk 0.2.4__tar.gz → 0.2.6__tar.gz

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 (60) hide show
  1. {clerk_sdk-0.2.4/clerk_sdk.egg-info → clerk_sdk-0.2.6}/PKG-INFO +1 -1
  2. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/client.py +11 -0
  3. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/client_actor/client_actor.py +2 -2
  4. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/decorators/gui_automation.py +14 -6
  5. clerk_sdk-0.2.6/clerk/gui_automation/ui_actions/support.py +124 -0
  6. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/state_machine.py +16 -0
  7. clerk_sdk-0.2.6/clerk/models/ui_operator.py +15 -0
  8. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6/clerk_sdk.egg-info}/PKG-INFO +1 -1
  9. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk_sdk.egg-info/SOURCES.txt +1 -0
  10. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/setup.py +1 -1
  11. clerk_sdk-0.2.4/clerk/gui_automation/ui_actions/support.py +0 -69
  12. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/LICENSE +0 -0
  13. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/MANIFEST.in +0 -0
  14. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/README.md +0 -0
  15. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/__init__.py +0 -0
  16. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/base.py +0 -0
  17. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/client.py +0 -0
  18. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/decorator/__init__.py +0 -0
  19. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/decorator/models.py +0 -0
  20. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/decorator/task_decorator.py +0 -0
  21. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/__init__.py +0 -0
  22. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/action_model/__init__.py +0 -0
  23. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/action_model/model.py +0 -0
  24. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/action_model/utils.py +0 -0
  25. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/client_actor/__init__.py +0 -0
  26. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/client_actor/exception.py +0 -0
  27. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/client_actor/model.py +0 -0
  28. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/decorators/__init__.py +0 -0
  29. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/exceptions/__init__.py +0 -0
  30. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/exceptions/agent_manager.py +0 -0
  31. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/exceptions/modality/__init__.py +0 -0
  32. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/exceptions/modality/exc.py +0 -0
  33. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/exceptions/websocket.py +0 -0
  34. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/requirements.txt +0 -0
  35. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_actions/__init__.py +0 -0
  36. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_actions/actions.py +0 -0
  37. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_actions/base.py +0 -0
  38. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_inspector/__init__.py +0 -0
  39. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_inspector/gui_vision.py +0 -0
  40. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_inspector/models.py +0 -0
  41. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/__init__.py +0 -0
  42. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/ai_recovery.py +0 -0
  43. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/decorators.py +0 -0
  44. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/exceptions.py +0 -0
  45. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/gui_automation/ui_state_machine/models.py +0 -0
  46. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/__init__.py +0 -0
  47. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/document.py +0 -0
  48. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/document_statuses.py +0 -0
  49. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/file.py +0 -0
  50. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/remote_device.py +0 -0
  51. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/models/response_model.py +0 -0
  52. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/utils/__init__.py +0 -0
  53. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/utils/logger.py +0 -0
  54. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk/utils/save_artifact.py +0 -0
  55. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk_sdk.egg-info/dependency_links.txt +0 -0
  56. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk_sdk.egg-info/requires.txt +0 -0
  57. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/clerk_sdk.egg-info/top_level.txt +0 -0
  58. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/pyproject.toml +0 -0
  59. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/requirements.txt +0 -0
  60. {clerk_sdk-0.2.4 → clerk_sdk-0.2.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clerk-sdk
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Library for interacting with Clerk
5
5
  Home-page: https://github.com/F-ONE-Group/clerk_pypi
6
6
  Author: F-ONE Group
@@ -11,6 +11,7 @@ from clerk.gui_automation.ui_state_inspector.models import (
11
11
  TargetWithAnchor,
12
12
  )
13
13
  from clerk.models.remote_device import RemoteDevice
14
+ from clerk.models.ui_operator import UiOperatorTask
14
15
 
15
16
 
16
17
  class RPAClerk(BaseClerk):
@@ -46,6 +47,16 @@ class RPAClerk(BaseClerk):
46
47
  raise RuntimeError("No coordinates found in the response.")
47
48
  return Coords(**res.data[0])
48
49
 
50
+ def create_ui_operator_task(self, payload: Dict) -> UiOperatorTask:
51
+ endpoint = "/ui_operator"
52
+ res = self.post_request(endpoint=endpoint, json=payload)
53
+ return UiOperatorTask(**res.data[0])
54
+
55
+ def get_ui_operator_task(self, id: str) -> UiOperatorTask:
56
+ endpoint = "/ui_operator"
57
+ res = self.get_request(endpoint=endpoint, params={"task_id": id})
58
+ return UiOperatorTask(**res.data[0])
59
+
49
60
 
50
61
  class GUIVisionClerk(BaseClerk):
51
62
  root_endpoint: str = "/gui_automation/vision"
@@ -66,7 +66,7 @@ async def _get_screen_async() -> str:
66
66
  and returns the base64 encoded image of the screen captured.
67
67
  """
68
68
  payload = {
69
- "proc_inst_id": os.getenv("PROC_ID"),
69
+ "proc_inst_id": os.getenv("_run_id"),
70
70
  "client_name": os.getenv("REMOTE_DEVICE_NAME"),
71
71
  "headless": True,
72
72
  "action": {"action_type": "screenshot"},
@@ -132,7 +132,7 @@ async def _perform_action_async(
132
132
  PerformActionException: If the action fails with an error message.
133
133
  """
134
134
  req_payload: Dict = {
135
- "proc_inst_id": os.getenv("PROC_ID"),
135
+ "proc_inst_id": os.getenv("_run_id"),
136
136
  "client_name": os.getenv("REMOTE_DEVICE_NAME"),
137
137
  "headless": (
138
138
  True if os.getenv("HEADLESS", "True").lower() == "true" else False
@@ -24,7 +24,9 @@ global_ws: Union[ClientConnection, None] = None
24
24
  clerk_client = RPAClerk()
25
25
  wss_uri = "wss://agent-manager.f-one.group/action"
26
26
 
27
- REMOTE_DEVICE_ALLOCATION_TIMEOUT = int(os.getenv("REMOTE_DEVICE_ALLOCATION_TIMEOUT", 1))
27
+ REMOTE_DEVICE_ALLOCATION_TIMEOUT = int(
28
+ os.getenv("REMOTE_DEVICE_ALLOCATION_TIMEOUT", 60)
29
+ )
28
30
  REMOTE_DEVICE_ALLOCATION_MAX_TRIES = int(
29
31
  os.getenv("REMOTE_DEVICE_ALLOCATION_MAX_TRIES", 60)
30
32
  )
@@ -48,13 +50,13 @@ def _allocate_remote_device(
48
50
 
49
51
  except NoClientsAvailable:
50
52
  logger.warning(
51
- f"No clients are available for {group_name} group. Initiating a {REMOTE_DEVICE_ALLOCATION_TIMEOUT} minute wait. Retry count: {retries}"
53
+ f"No clients are available for {group_name} group. Initiating a {REMOTE_DEVICE_ALLOCATION_TIMEOUT} seconds wait. Retry count: {retries}"
52
54
  )
53
55
  if retries >= REMOTE_DEVICE_ALLOCATION_MAX_TRIES:
54
56
  raise ClientAvailabilityTimeout(
55
- f"No clients available for {group_name} group after {REMOTE_DEVICE_ALLOCATION_TIMEOUT * REMOTE_DEVICE_ALLOCATION_MAX_TRIES} minutes"
57
+ f"No clients available for {group_name} group after {REMOTE_DEVICE_ALLOCATION_TIMEOUT * REMOTE_DEVICE_ALLOCATION_MAX_TRIES} seconds"
56
58
  )
57
- time.sleep(REMOTE_DEVICE_ALLOCATION_TIMEOUT * 60)
59
+ time.sleep(REMOTE_DEVICE_ALLOCATION_TIMEOUT)
58
60
  retries += 1
59
61
 
60
62
 
@@ -93,7 +95,8 @@ def gui_automation(
93
95
  def wrapper(payload: ClerkCodePayload, *args, **kwargs):
94
96
  global global_ws
95
97
  force_deallocate = False
96
- os.environ["PROC_ID"] = payload.run_id
98
+ os.environ["_document_id"] = payload.document.id
99
+ os.environ["_run_id"] = payload.run_id
97
100
 
98
101
  remote_device = _allocate_remote_device(
99
102
  clerk_client, group_name, payload.run_id
@@ -120,12 +123,17 @@ def gui_automation(
120
123
  raise WebSocketConnectionFailed()
121
124
 
122
125
  except Exception as e:
123
- os.environ.pop("PROC_ID", None)
124
126
  force_deallocate = True
125
127
  raise
126
128
  finally:
129
+ os.environ.pop("_run_id", None)
130
+ os.environ.pop("_document_id", None)
127
131
  if not reserve_client or force_deallocate:
128
132
  _deallocate_target(clerk_client, remote_device, payload.run_id)
133
+ else:
134
+ logger.warning(
135
+ f"The client stayed reserved for the this run id: {payload.run_id}"
136
+ )
129
137
 
130
138
  if global_ws and global_ws.state is State.OPEN:
131
139
  close_task = event_loop.create_task(close_ws_connection(global_ws))
@@ -0,0 +1,124 @@
1
+ from datetime import timedelta, datetime
2
+ import os
3
+ import base64
4
+ import time
5
+ from typing import Optional
6
+ from backoff._typing import Details
7
+
8
+ from clerk.models.ui_operator import TaskStatuses, UiOperatorTask
9
+ from clerk.utils.save_artifact import save_artifact
10
+ from clerk.utils import logger
11
+ from ..client_actor import get_screen
12
+ from ..ui_actions.base import BaseAction
13
+ from ..decorators.gui_automation import clerk_client
14
+
15
+
16
+ _MAP = {
17
+ "y": True,
18
+ "yes": True,
19
+ "t": True,
20
+ "true": True,
21
+ "on": True,
22
+ "1": True,
23
+ "n": False,
24
+ "no": False,
25
+ "f": False,
26
+ "false": False,
27
+ "off": False,
28
+ "0": False,
29
+ }
30
+
31
+
32
+ def strtobool(value):
33
+ try:
34
+ return _MAP[str(value).lower()]
35
+ except KeyError:
36
+ raise ValueError('"{}" is not a valid bool value'.format(value))
37
+
38
+
39
+ def save_screenshot(filename: str, sub_folder: Optional[str] = None) -> str:
40
+ """
41
+ Save a screenshot into the process instance folder.
42
+
43
+ This function retrieves the base64 representation of the screen from the target environment using the 'get_screen' function.
44
+ Then, it saves the screenshot into the process instance folder using the 'save_file_into_instance_folder' function.
45
+
46
+ Args:
47
+ filename (str): The name of the file to save the screenshot as.
48
+ sub_folder (str, optional): The name of the subfolder within the instance folder where the screenshot will be saved. Defaults to None.
49
+
50
+ Returns:
51
+ str: The file path of the saved screenshot.
52
+
53
+ """
54
+ # get the base64 screen from target environment
55
+ screen_b64: str = get_screen()
56
+ return save_artifact(
57
+ filename=filename,
58
+ file_bytes=base64.b64decode(screen_b64),
59
+ subfolder=sub_folder,
60
+ )
61
+
62
+
63
+ def _format_action_string(action: BaseAction) -> str:
64
+ """
65
+ Formats action in the same format as the one used in task modules.
66
+ """
67
+ action_string = (
68
+ f"{action.__class__.__name__}(target='{action.target_name or action.target}')"
69
+ )
70
+ for anchor in action.anchors:
71
+ action_string += f".{anchor.relation}('{anchor.value}')"
72
+ if action.click_offset != [0, 0]:
73
+ action_string += (
74
+ f".offset(x={action.click_offset[0]}, y={action.click_offset[1]})"
75
+ )
76
+ action_string += ".do()"
77
+ return action_string
78
+
79
+
80
+ def maybe_engage_operator_ui_action(details: Details) -> None:
81
+ """
82
+ Makes a call to the operator queue server to create an issue and waits for the allotted time for it to be resolved.
83
+ :param details: A dictionary containing the details of the exception raised (https://pypi.org/project/backoff/)
84
+ :returns: None
85
+ :raises: The exception raised by the action if the issue is not resolved within the allotted time
86
+ """
87
+ # Determine if the operator should be engaged
88
+ ui_operator_enabled = strtobool(os.getenv("_ui_operator_enabled", default="False"))
89
+
90
+ if not ui_operator_enabled:
91
+ raise details["exception"] # type: ignore
92
+
93
+ ui_operator_pooling_interval = int(os.getenv("_ui_operator_pooling_interval", "1"))
94
+ ui_operator_timeout = int(os.getenv("_ui_operator_timeout", "3600"))
95
+ resolution_deadline = datetime.now() + timedelta(seconds=ui_operator_timeout)
96
+
97
+ # Extract the action object from the details dictionary
98
+ action: BaseAction = details["args"][0]
99
+ issue_description = _format_action_string(action)
100
+
101
+ # create ui operator task
102
+ payload = {
103
+ "document_id": os.getenv("_document_id"),
104
+ "remote_device_id": os.getenv("REMOTE_DEVICE_ID"),
105
+ "issue_description": issue_description,
106
+ }
107
+ task: UiOperatorTask = clerk_client.create_ui_operator_task(payload)
108
+ while datetime.now() < resolution_deadline:
109
+ task: UiOperatorTask = clerk_client.get_ui_operator_task(task.id)
110
+ if task.status == TaskStatuses.COMPLETED:
111
+ logger.debug(
112
+ f"The ui operator task {task.id} has been resolved by {task.assignee_name}"
113
+ )
114
+ return
115
+ elif task.status == TaskStatuses.CANCELLED:
116
+ logger.warning(f"The ui operator task {task.id} has been cancelled")
117
+ raise details["exception"]
118
+
119
+ time.sleep(ui_operator_pooling_interval)
120
+
121
+ logger.warning(
122
+ f"The ui operator task {task.id} was not resolved after {ui_operator_timeout} seconds"
123
+ )
124
+ raise details["exception"]
@@ -44,6 +44,9 @@ class ScreenPilot:
44
44
  tolerate_repeat_transitions (int): Number of repeated transitions to tolerate before breaking the execution. Default 5.
45
45
  tolerate_repeat_states (int): Number of repeated states to tolerate before breaking the execution. Default 5.
46
46
  enable_force_close_app_process (bool): If true, terminates the application process via `taskkill` command. Default False.
47
+ ui_operator_enabled (bool): if true, enables the creation of ui operator task which needs to be resolved in Clerk.
48
+ ui_operator_pooling_interval (int): in seconds, defines the time pooling interval for ui operator task. Default 1.
49
+ ui_operator_timeout (int): in seconds, defines the max waiting time for the ui operator task to be resolved before raising and exception.
47
50
  process_name (Optional[str]): Name of the process that needs to be closed (ie. process.exe). Required attribute if `enable_force_close_app_process` is True
48
51
 
49
52
  Methods:
@@ -63,6 +66,9 @@ class ScreenPilot:
63
66
  tolerate_repeat_transitions: int = 5
64
67
  tolerate_repeat_states: int = 5
65
68
  enable_force_close_app_process: bool = False
69
+ ui_operator_enabled: bool = False
70
+ ui_operator_pooling_interval: int = 1 # seconds
71
+ ui_operator_timeout: int = 3600 # seconds (1 hour)
66
72
  process_name: Optional[str] = None
67
73
  _acted_since_state_eval: bool = False
68
74
  _ai_recovery_agent: Optional[CourseCorrector] = None
@@ -716,6 +722,14 @@ class ScreenPilot:
716
722
  """
717
723
  return None
718
724
 
725
+ @classmethod
726
+ def _initialize_env_variables(cls):
727
+ os.environ["_ui_operator_enabled"] = str(cls.ui_operator_enabled)
728
+ os.environ["_ui_operator_pooling_interval"] = str(
729
+ cls.ui_operator_pooling_interval
730
+ )
731
+ os.environ["_ui_operator_timeout"] = str(cls.ui_operator_timeout)
732
+
719
733
  @classmethod
720
734
  def run(
721
735
  cls, goal_function: Optional[Callable] = None, **kwargs
@@ -732,6 +746,8 @@ class ScreenPilot:
732
746
  Returns:
733
747
  - Exit reason (ScreenPilotOutcome): Exception class that interrupted the state machine execution.
734
748
  """
749
+ cls._initialize_env_variables()
750
+
735
751
  if not goal_function:
736
752
  goal_function = cls._default_goal_function
737
753
  cls._act_on_start()
@@ -0,0 +1,15 @@
1
+ from enum import Enum
2
+ from typing import Optional
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class TaskStatuses(str, Enum):
7
+ OPEN = "open"
8
+ COMPLETED = "completed"
9
+ CANCELLED = "cancelled"
10
+
11
+
12
+ class UiOperatorTask(BaseModel):
13
+ id: str
14
+ status: TaskStatuses
15
+ assignee_name: Optional[str]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clerk-sdk
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Library for interacting with Clerk
5
5
  Home-page: https://github.com/F-ONE-Group/clerk_pypi
6
6
  Author: F-ONE Group
@@ -46,6 +46,7 @@ clerk/models/document_statuses.py
46
46
  clerk/models/file.py
47
47
  clerk/models/remote_device.py
48
48
  clerk/models/response_model.py
49
+ clerk/models/ui_operator.py
49
50
  clerk/utils/__init__.py
50
51
  clerk/utils/logger.py
51
52
  clerk/utils/save_artifact.py
@@ -13,7 +13,7 @@ gui_requirements = get_requirements("./clerk/gui_automation")
13
13
 
14
14
  setup(
15
15
  name="clerk-sdk",
16
- version="0.2.4",
16
+ version="0.2.6",
17
17
  description="Library for interacting with Clerk",
18
18
  long_description=open("README.md").read(),
19
19
  long_description_content_type="text/markdown",
@@ -1,69 +0,0 @@
1
- import os
2
- import base64
3
- from typing import Optional
4
- from backoff._typing import Details
5
-
6
- from clerk.utils.save_artifact import save_artifact
7
- from ..client_actor import get_screen
8
-
9
-
10
- _MAP = {
11
- "y": True,
12
- "yes": True,
13
- "t": True,
14
- "true": True,
15
- "on": True,
16
- "1": True,
17
- "n": False,
18
- "no": False,
19
- "f": False,
20
- "false": False,
21
- "off": False,
22
- "0": False,
23
- }
24
-
25
-
26
- def strtobool(value):
27
- try:
28
- return _MAP[str(value).lower()]
29
- except KeyError:
30
- raise ValueError('"{}" is not a valid bool value'.format(value))
31
-
32
-
33
- def save_screenshot(filename: str, sub_folder: Optional[str] = None) -> str:
34
- """
35
- Save a screenshot into the process instance folder.
36
-
37
- This function retrieves the base64 representation of the screen from the target environment using the 'get_screen' function.
38
- Then, it saves the screenshot into the process instance folder using the 'save_file_into_instance_folder' function.
39
-
40
- Args:
41
- filename (str): The name of the file to save the screenshot as.
42
- sub_folder (str, optional): The name of the subfolder within the instance folder where the screenshot will be saved. Defaults to None.
43
-
44
- Returns:
45
- str: The file path of the saved screenshot.
46
-
47
- """
48
- # get the base64 screen from target environment
49
- screen_b64: str = get_screen()
50
- return save_artifact(
51
- filename=filename,
52
- file_bytes=base64.b64decode(screen_b64),
53
- subfolder=sub_folder,
54
- )
55
-
56
-
57
- def maybe_engage_operator_ui_action(details: Details) -> None:
58
- """
59
- Makes a call to the operator queue server to create an issue and waits for the allotted time for it to be resolved.
60
- :param details: A dictionary containing the details of the exception raised (https://pypi.org/project/backoff/)
61
- :returns: None
62
- :raises: The exception raised by the action if the issue is not resolved within the allotted time
63
- """
64
- # Determine if the operator should be engaged
65
- use_operator = strtobool(os.getenv("USE_OPERATOR", default="False"))
66
- if not use_operator:
67
- raise details["exception"] # type: ignore
68
-
69
- raise NotImplementedError("Feature not yet implemented")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes