clerk-sdk 0.1.8__py3-none-any.whl → 0.2.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 (42) hide show
  1. clerk/base.py +94 -0
  2. clerk/client.py +3 -104
  3. clerk/decorator/models.py +1 -0
  4. clerk/decorator/task_decorator.py +4 -1
  5. clerk/gui_automation/__init__.py +0 -0
  6. clerk/gui_automation/action_model/__init__.py +0 -0
  7. clerk/gui_automation/action_model/model.py +126 -0
  8. clerk/gui_automation/action_model/utils.py +26 -0
  9. clerk/gui_automation/client.py +144 -0
  10. clerk/gui_automation/client_actor/__init__.py +4 -0
  11. clerk/gui_automation/client_actor/client_actor.py +178 -0
  12. clerk/gui_automation/client_actor/exception.py +22 -0
  13. clerk/gui_automation/client_actor/model.py +192 -0
  14. clerk/gui_automation/decorators/__init__.py +1 -0
  15. clerk/gui_automation/decorators/gui_automation.py +109 -0
  16. clerk/gui_automation/exceptions/__init__.py +0 -0
  17. clerk/gui_automation/exceptions/modality/__init__.py +0 -0
  18. clerk/gui_automation/exceptions/modality/exc.py +46 -0
  19. clerk/gui_automation/exceptions/websocket.py +6 -0
  20. clerk/gui_automation/ui_actions/__init__.py +1 -0
  21. clerk/gui_automation/ui_actions/actions.py +781 -0
  22. clerk/gui_automation/ui_actions/base.py +200 -0
  23. clerk/gui_automation/ui_actions/support.py +68 -0
  24. clerk/gui_automation/ui_state_inspector/__init__.py +0 -0
  25. clerk/gui_automation/ui_state_inspector/gui_vision.py +184 -0
  26. clerk/gui_automation/ui_state_inspector/models.py +184 -0
  27. clerk/gui_automation/ui_state_machine/__init__.py +11 -0
  28. clerk/gui_automation/ui_state_machine/ai_recovery.py +110 -0
  29. clerk/gui_automation/ui_state_machine/decorators.py +71 -0
  30. clerk/gui_automation/ui_state_machine/exceptions.py +42 -0
  31. clerk/gui_automation/ui_state_machine/models.py +40 -0
  32. clerk/gui_automation/ui_state_machine/state_machine.py +838 -0
  33. clerk/models/remote_device.py +7 -0
  34. clerk/utils/__init__.py +0 -0
  35. clerk/utils/logger.py +118 -0
  36. clerk/utils/save_artifact.py +35 -0
  37. {clerk_sdk-0.1.8.dist-info → clerk_sdk-0.2.0.dist-info}/METADATA +11 -1
  38. clerk_sdk-0.2.0.dist-info/RECORD +48 -0
  39. clerk_sdk-0.1.8.dist-info/RECORD +0 -15
  40. {clerk_sdk-0.1.8.dist-info → clerk_sdk-0.2.0.dist-info}/WHEEL +0 -0
  41. {clerk_sdk-0.1.8.dist-info → clerk_sdk-0.2.0.dist-info}/licenses/LICENSE +0 -0
  42. {clerk_sdk-0.1.8.dist-info → clerk_sdk-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,110 @@
1
+ from typing import Union, List, Optional, Type
2
+ from pydantic import BaseModel, Field
3
+
4
+ from clerk.gui_automation.client import CourseCorrectorClerk
5
+
6
+ from ..client_actor.client_actor import get_screen
7
+ from .models import ActionString
8
+
9
+
10
+ class CourseCorrector(BaseModel):
11
+ """
12
+ Interface for a CourseCorrector class that can generate corrective actions based on a goal and feedback.
13
+ """
14
+
15
+ name: str
16
+ goal: str
17
+ custom_instructions: Optional[str] = None
18
+
19
+ def get_corrective_actions(
20
+ self, output_model: Type[ActionString] = ActionString
21
+ ) -> List[ActionString]:
22
+ """
23
+ Writes an action string based on the provided prompt.
24
+ Args:
25
+ action_prompt: The prompt for the action to write.
26
+ output_model: The model to use for the response.
27
+ Returns:
28
+ List of ActionString models.
29
+ """
30
+ raise NotImplementedError("get_corrective_action method is not implemented")
31
+
32
+ def add_feedback(self, feedback: str) -> None:
33
+ """
34
+ Adds feedback to the CourseCorrector instance.
35
+ Args:
36
+ feedback: The feedback to add.
37
+ """
38
+ raise NotImplementedError("add_feedback method is not implemented")
39
+
40
+ def get_latest_feedback(self) -> Optional[str]:
41
+ """
42
+ Gets the latest feedback added to the CourseCorrector instance.
43
+ Returns:
44
+ The latest feedback as a string, or None if no feedback has been added.
45
+ """
46
+ raise NotImplementedError("get_latest_feedback method is not implemented")
47
+
48
+ def reset_feedback(self) -> None:
49
+ """
50
+ Resets the latest feedback added to the CourseCorrector instance.
51
+ """
52
+ raise NotImplementedError("reset_feedback method is not implemented")
53
+
54
+
55
+ class CourseCorrectorV1(CourseCorrector):
56
+ name: str = "CourseCorrectorV1"
57
+ use_ocr: bool = Field(
58
+ default=True,
59
+ description="Whether OCR of the screen should be included with in the model call (increases precision with "
60
+ "small details).",
61
+ )
62
+ clerk_client: CourseCorrectorClerk = CourseCorrectorClerk()
63
+
64
+ def get_corrective_actions(
65
+ self,
66
+ output_model: Type[ActionString] = ActionString,
67
+ ) -> List[ActionString]:
68
+ """
69
+ Writes an action string based on the provided prompt.
70
+ Args:
71
+ action_prompt: The prompt for the action to write.
72
+ output_model: The model to use for the response.
73
+ Returns:
74
+ List of ActionString models.
75
+ """
76
+ screen_b64 = get_screen()
77
+ action_string = self.clerk_client.get_corrective_actions(
78
+ screen_b64, self.use_ocr, self.goal, self.custom_instructions
79
+ )
80
+ assert isinstance(action_string, ActionString)
81
+ return [action_string]
82
+
83
+ def add_feedback(self, feedback: str) -> None:
84
+ """
85
+ Adds feedback to the CourseCorrector instance.
86
+ Args:
87
+ feedback: The feedback to add.
88
+ """
89
+ self.latest_feedback = feedback
90
+
91
+ def get_latest_feedback(self) -> Optional[str]:
92
+ """
93
+ Gets the latest feedback added to the CourseCorrector instance.
94
+ Returns:
95
+ The latest feedback as a string, or None if no feedback has been added.
96
+ """
97
+ return self.latest_feedback
98
+
99
+ def reset_feedback(self) -> None:
100
+ """
101
+ Resets the latest feedback added to the CourseCorrector instance.
102
+ """
103
+ self.latest_feedback = None
104
+
105
+
106
+ def course_corrector_v1(
107
+ goal: str, custom_instructions: Union[str, None] = None
108
+ ) -> CourseCorrectorV1:
109
+ """Factory function for generating a CourseCorrector instance with the specified goal."""
110
+ return CourseCorrectorV1(goal=goal, custom_instructions=custom_instructions)
@@ -0,0 +1,71 @@
1
+ from typing import Callable, Optional
2
+ from .state_machine import ScreenPilot
3
+
4
+
5
+ def state(*args, start_allowed=True, end_allowed=True):
6
+ """
7
+ Register a state class with the ScreenPilot state machine.
8
+
9
+ Parameters:
10
+ - start_allowed (bool): Whether the process may start from this state.
11
+ - end_allowed (bool): Whether the process may end in this state.
12
+
13
+ Returns:
14
+ - None
15
+
16
+ Example:
17
+ @state(start_allowed=True, end_allowed=False)
18
+ """
19
+ if args and callable(args[0]):
20
+ # It's used as @state without arguments, args[0] is the class
21
+ cls = args[0]
22
+ return state()(cls) # Apply default arguments
23
+ else:
24
+
25
+ def class_decorator(cls):
26
+ ScreenPilot.register_state(
27
+ cls, start_allowed=start_allowed, end_allowed=end_allowed
28
+ )
29
+ return cls
30
+
31
+ return class_decorator
32
+
33
+
34
+ def transition(from_state: str, to_state: str, condition: Optional[Callable] = None):
35
+ """
36
+ Register a transition between two states with the ScreenPilot state machine.
37
+
38
+ Parameters:
39
+ - from_state (str): The name of the state to transition from.
40
+ - to_state (str): The name of the state to transition to.
41
+ - condition (Callable): Condition to disambiguate between multiple transitions. Must return a boolean.
42
+
43
+ Returns:
44
+ - None
45
+
46
+ Example:
47
+ @transition('StateA', 'StateB')
48
+ """
49
+ return ScreenPilot.register_transition(
50
+ from_state, to_state, mode="planned", condition=condition
51
+ )
52
+
53
+
54
+ def rollback(from_state: str, to_state: str, condition: Optional[Callable] = None):
55
+ """
56
+ Register a rollback transition between two states with the ScreenPilot state machine.
57
+
58
+ Parameters:
59
+ - from_state (str): The name of the state to transition from.
60
+ - to_state (str): The name of the state to transition to.
61
+ - condition (Callable): Condition to disambiguate between multiple rollbacks. Must return a boolean.
62
+
63
+ Returns:
64
+ - None
65
+
66
+ Example:
67
+ @rollback('StateA', 'StateB')
68
+ """
69
+ return ScreenPilot.register_transition(
70
+ from_state, to_state, mode="rollback", condition=condition
71
+ )
@@ -0,0 +1,42 @@
1
+ from typing import Optional
2
+
3
+
4
+ class ScreenPilotOutcome(Exception):
5
+ """Base class for all exceptions and conditions raised by the ScreenPilot state machine."""
6
+
7
+
8
+ class ScreenPilotException(Exception):
9
+ """Base class for all exceptions raised by the ScreenPilot state machine."""
10
+
11
+
12
+ class BusinessException(ScreenPilotOutcome):
13
+ """Raised from inside transitions to indicate a business process condition."""
14
+
15
+
16
+ class UnplannedTransitionsError(ScreenPilotException):
17
+ """Raised when a transition occurs that is not planned in the state machine."""
18
+
19
+
20
+ class RepeatStatesError(ScreenPilotException):
21
+ """Raised when an attempt is made to re-enter a state that should not be repeated."""
22
+
23
+
24
+ class RepeatTransitions(ScreenPilotException):
25
+ """Raised when the same transition is attempted to be repeated in an invalid context."""
26
+
27
+
28
+ class CourseCorrectionImpossible(ScreenPilotException):
29
+ """Raised when the state machine cannot determine a course correction."""
30
+
31
+
32
+ class SuccessfulCompletion(ScreenPilotOutcome):
33
+ """Raised when the state machine has completed successfully."""
34
+
35
+
36
+ class RollbackCompleted(ScreenPilotOutcome):
37
+ """Raised when the state machine has completed a rollback successfully."""
38
+
39
+
40
+ def complete_ui_automation(message: Optional[str] = None):
41
+ """Raise an exception to interrupt ScreenPilot and indicate that the UI automation has completed successfully."""
42
+ raise SuccessfulCompletion(message)
@@ -0,0 +1,40 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel, field_validator, model_validator
3
+
4
+
5
+ class ActionString(BaseModel):
6
+ """
7
+ ActionString class represents a string that represents an action in an application.
8
+
9
+ Attributes:
10
+ action_string (str): The string representation of the action.
11
+ comment (str, optional): An optional comment or description for the action.
12
+ interrupt_process (bool, optional): A flag indicating whether the action should interrupt the process.
13
+
14
+ Methods:
15
+ ensure_format(v: str) -> str:
16
+ Validator function that ensures the action string has the correct format.
17
+
18
+ """
19
+
20
+ action_string: str
21
+ action_comment: Optional[str] = None
22
+ observation: Optional[str] = None
23
+ interrupt_process: Optional[bool] = False
24
+
25
+ @field_validator("action_string", mode="before")
26
+ @classmethod
27
+ def ensure_format(cls, v):
28
+ if not isinstance(v, str):
29
+ raise ValueError("Action string must be a string")
30
+ if not v.endswith(".do()") and not v.startswith("NoAction"):
31
+ raise ValueError("Action string must end with '.do()'")
32
+ return v
33
+
34
+ @field_validator("interrupt_process", mode="before")
35
+ def convert_to_bool(cls, v):
36
+ if v is None:
37
+ return False
38
+ elif isinstance(v, str):
39
+ return v.lower() in ["true", "1", "yes"]
40
+ return v