clerk-sdk 0.3.7__py3-none-any.whl → 0.4.1__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.
- clerk/base.py +47 -13
- clerk/client.py +19 -2
- clerk/decorator/__init__.py +2 -0
- clerk/decorator/models.py +2 -2
- clerk/decorator/task_decorator.py +12 -6
- clerk/exceptions/exceptions.py +7 -7
- clerk/gui_automation/action_model/model.py +1 -1
- clerk/gui_automation/client.py +16 -12
- clerk/gui_automation/client_actor/client_actor.py +3 -3
- clerk/gui_automation/client_actor/model.py +16 -13
- clerk/gui_automation/decorators/gui_automation.py +1 -1
- clerk/gui_automation/ui_actions/actions.py +24 -24
- clerk/gui_automation/ui_actions/base.py +5 -2
- clerk/gui_automation/ui_state_inspector/gui_vision.py +2 -2
- clerk/gui_automation/ui_state_inspector/models.py +5 -5
- clerk/gui_automation/ui_state_machine/models.py +4 -4
- clerk/models/document.py +64 -3
- clerk/models/file.py +4 -2
- {clerk_sdk-0.3.7.dist-info → clerk_sdk-0.4.1.dist-info}/METADATA +1 -1
- {clerk_sdk-0.3.7.dist-info → clerk_sdk-0.4.1.dist-info}/RECORD +23 -23
- {clerk_sdk-0.3.7.dist-info → clerk_sdk-0.4.1.dist-info}/WHEEL +0 -0
- {clerk_sdk-0.3.7.dist-info → clerk_sdk-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {clerk_sdk-0.3.7.dist-info → clerk_sdk-0.4.1.dist-info}/top_level.txt +0 -0
clerk/base.py
CHANGED
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
|
|
3
3
|
import requests
|
|
4
4
|
import backoff
|
|
5
|
-
from typing import Dict, Optional, Self
|
|
5
|
+
from typing import Any, Dict, List, Optional, Self, Tuple
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
from pydantic import BaseModel, model_validator, Field
|
|
@@ -10,7 +10,7 @@ from pydantic import BaseModel, model_validator, Field
|
|
|
10
10
|
from .models.response_model import StandardResponse
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def giveup_handler(e):
|
|
13
|
+
def giveup_handler(e: Any):
|
|
14
14
|
return (
|
|
15
15
|
isinstance(e, requests.exceptions.HTTPError)
|
|
16
16
|
and e.response is not None
|
|
@@ -42,16 +42,15 @@ class BaseClerk(BaseModel):
|
|
|
42
42
|
(requests.exceptions.RequestException,),
|
|
43
43
|
max_tries=3,
|
|
44
44
|
jitter=None,
|
|
45
|
-
# on_backoff=backoff_handler,
|
|
46
45
|
giveup=giveup_handler,
|
|
47
46
|
)
|
|
48
47
|
def get_request(
|
|
49
48
|
self,
|
|
50
49
|
endpoint: str,
|
|
51
50
|
headers: Dict[str, str] = {},
|
|
52
|
-
json: Dict = {},
|
|
53
|
-
params: Dict = {},
|
|
54
|
-
) -> StandardResponse:
|
|
51
|
+
json: Dict[str, Any] = {},
|
|
52
|
+
params: Dict[str, Any] = {},
|
|
53
|
+
) -> StandardResponse[Dict[str, Any]]:
|
|
55
54
|
|
|
56
55
|
merged_headers = {**self.headers, **headers}
|
|
57
56
|
url = f"{self.base_url}{endpoint}"
|
|
@@ -70,18 +69,17 @@ class BaseClerk(BaseModel):
|
|
|
70
69
|
(requests.exceptions.RequestException,),
|
|
71
70
|
max_tries=3,
|
|
72
71
|
jitter=None,
|
|
73
|
-
# on_backoff=backoff_handler,
|
|
74
72
|
giveup=giveup_handler,
|
|
75
73
|
)
|
|
76
74
|
def post_request(
|
|
77
75
|
self,
|
|
78
76
|
endpoint: str,
|
|
79
77
|
headers: Dict[str, str] = {},
|
|
80
|
-
json: Dict = {},
|
|
81
|
-
params: Dict = {},
|
|
82
|
-
data: Dict = None,
|
|
83
|
-
files:
|
|
84
|
-
) -> StandardResponse:
|
|
78
|
+
json: Dict[str, Any] = {},
|
|
79
|
+
params: Dict[str, Any] = {},
|
|
80
|
+
data: Dict[str, Any] | None = None,
|
|
81
|
+
files: List[Tuple[str, Tuple[str, bytes, str | None]]] | None = None,
|
|
82
|
+
) -> StandardResponse[Dict[str, Any]]:
|
|
85
83
|
|
|
86
84
|
merged_headers = {**self.headers, **headers}
|
|
87
85
|
url = f"{self.base_url}{endpoint}"
|
|
@@ -96,7 +94,43 @@ class BaseClerk(BaseModel):
|
|
|
96
94
|
json=json,
|
|
97
95
|
params=params,
|
|
98
96
|
data=data,
|
|
99
|
-
files=files,
|
|
97
|
+
files=files, # type: ignore
|
|
98
|
+
)
|
|
99
|
+
response.raise_for_status()
|
|
100
|
+
|
|
101
|
+
return StandardResponse(**response.json())
|
|
102
|
+
|
|
103
|
+
@backoff.on_exception(
|
|
104
|
+
backoff.expo,
|
|
105
|
+
(requests.exceptions.RequestException,),
|
|
106
|
+
max_tries=3,
|
|
107
|
+
jitter=None,
|
|
108
|
+
giveup=giveup_handler,
|
|
109
|
+
)
|
|
110
|
+
def put_request(
|
|
111
|
+
self,
|
|
112
|
+
endpoint: str,
|
|
113
|
+
headers: Dict[str, str] = {},
|
|
114
|
+
json: Dict[str, Any] = {},
|
|
115
|
+
params: Dict[str, Any] = {},
|
|
116
|
+
data: Dict[str, Any] | None = None,
|
|
117
|
+
files: List[Tuple[str, Tuple[str, bytes, str | None]]] | None = None,
|
|
118
|
+
) -> StandardResponse[Dict[str, Any]]:
|
|
119
|
+
|
|
120
|
+
merged_headers = {**self.headers, **headers}
|
|
121
|
+
url = f"{self.base_url}{endpoint}"
|
|
122
|
+
if self.root_endpoint:
|
|
123
|
+
url = f"{self.base_url}{self.root_endpoint}{endpoint}"
|
|
124
|
+
|
|
125
|
+
# logger.info(f"POST {url} | body={json} | params={params}")
|
|
126
|
+
|
|
127
|
+
response = requests.put(
|
|
128
|
+
url,
|
|
129
|
+
headers=merged_headers,
|
|
130
|
+
json=json,
|
|
131
|
+
params=params,
|
|
132
|
+
data=data,
|
|
133
|
+
files=files, # type: ignore
|
|
100
134
|
)
|
|
101
135
|
response.raise_for_status()
|
|
102
136
|
|
clerk/client.py
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
from typing import List, Literal
|
|
2
|
-
from xml.dom.minidom import Document
|
|
1
|
+
from typing import Any, Dict, List, Literal
|
|
3
2
|
|
|
4
3
|
from clerk.base import BaseClerk
|
|
4
|
+
from clerk.models.document import Document, UploadDocumentRequest
|
|
5
5
|
from .models.file import ParsedFile, UploadFile
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Clerk(BaseClerk):
|
|
9
|
+
|
|
10
|
+
def upload_document(self, request: UploadDocumentRequest) -> Document:
|
|
11
|
+
endpoint = "/document"
|
|
12
|
+
res = self.post_request(
|
|
13
|
+
endpoint=endpoint, data=request.data, files=request.files_
|
|
14
|
+
)
|
|
15
|
+
return Document(**res.data[0])
|
|
16
|
+
|
|
17
|
+
def update_document_structured_data(
|
|
18
|
+
self, document_id: str, updated_structured_data: Dict[str, Any]
|
|
19
|
+
) -> Document:
|
|
20
|
+
endpoint = f"/document/{document_id}"
|
|
21
|
+
payload = dict(structured_data=updated_structured_data)
|
|
22
|
+
res = self.put_request(endpoint, json=payload)
|
|
23
|
+
|
|
24
|
+
return Document(**res.data[0])
|
|
25
|
+
|
|
9
26
|
def get_document(self, document_id: str) -> Document:
|
|
10
27
|
endpoint = f"/document/{document_id}"
|
|
11
28
|
res = self.get_request(endpoint=endpoint)
|
clerk/decorator/__init__.py
CHANGED
clerk/decorator/models.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Dict, List, Optional
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
|
|
4
4
|
|
|
@@ -16,5 +16,5 @@ class Document(BaseModel):
|
|
|
16
16
|
|
|
17
17
|
class ClerkCodePayload(BaseModel):
|
|
18
18
|
document: Document
|
|
19
|
-
structured_data: Dict
|
|
19
|
+
structured_data: Dict[str, Any]
|
|
20
20
|
run_id: Optional[str] = None
|
|
@@ -13,17 +13,19 @@ output_pkl: str = "/app/data/output/output.pkl"
|
|
|
13
13
|
def clerk_code():
|
|
14
14
|
def decorator(func: Callable[[ClerkCodePayload], ClerkCodePayload]):
|
|
15
15
|
@wraps(func)
|
|
16
|
-
def wrapper(
|
|
16
|
+
def wrapper(
|
|
17
|
+
payload: Optional[ClerkCodePayload] = None,
|
|
18
|
+
) -> ClerkCodePayload | None:
|
|
17
19
|
# 1. Load payload from file if not provided
|
|
18
20
|
use_pickle = False
|
|
19
|
-
output = None
|
|
21
|
+
output: ClerkCodePayload | BaseException | None = None
|
|
20
22
|
error_occurred = False
|
|
21
23
|
error_info = None
|
|
22
24
|
if payload is None:
|
|
23
25
|
use_pickle = True
|
|
24
|
-
# Write a placeholder output file in case of early failure
|
|
26
|
+
# Write a placeholder output file in case of early failure
|
|
25
27
|
with open(output_pkl, "wb") as f:
|
|
26
|
-
pickle.dump({"error": "Early failure"}, f)
|
|
28
|
+
pickle.dump({"error": "Early failure"}, f)
|
|
27
29
|
try:
|
|
28
30
|
with open(input_pkl, "rb") as f:
|
|
29
31
|
raw_data = pickle.load(f)
|
|
@@ -40,11 +42,13 @@ def clerk_code():
|
|
|
40
42
|
traceback=traceback.format_exc(),
|
|
41
43
|
)
|
|
42
44
|
|
|
45
|
+
assert payload is not None
|
|
46
|
+
|
|
43
47
|
# 2. Execute function
|
|
44
48
|
if not error_occurred:
|
|
45
49
|
try:
|
|
46
50
|
output = func(payload)
|
|
47
|
-
if not isinstance(output, ClerkCodePayload):
|
|
51
|
+
if not isinstance(output, ClerkCodePayload): # type: ignore
|
|
48
52
|
raise TypeError(
|
|
49
53
|
"Function must return a ClerkCodePayload instance."
|
|
50
54
|
)
|
|
@@ -55,10 +59,11 @@ def clerk_code():
|
|
|
55
59
|
message=str(e),
|
|
56
60
|
traceback=traceback.format_exc(),
|
|
57
61
|
)
|
|
62
|
+
output = error_info
|
|
58
63
|
|
|
59
64
|
# 3. write to output.pkl
|
|
60
65
|
try:
|
|
61
|
-
if use_pickle:
|
|
66
|
+
if use_pickle and output is not None:
|
|
62
67
|
with open(output_pkl, "wb") as f:
|
|
63
68
|
if error_occurred:
|
|
64
69
|
pickle.dump(error_info, f)
|
|
@@ -66,6 +71,7 @@ def clerk_code():
|
|
|
66
71
|
pickle.dump(output, f)
|
|
67
72
|
else:
|
|
68
73
|
pickle.dump(output.model_dump(mode="json"), f)
|
|
74
|
+
|
|
69
75
|
except Exception as e:
|
|
70
76
|
# If writing output.pkl fails, try to write a minimal error
|
|
71
77
|
try:
|
clerk/exceptions/exceptions.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Any, Optional
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class AppBaseException(Exception):
|
|
5
5
|
def __init__(
|
|
6
6
|
self,
|
|
7
|
-
*args,
|
|
7
|
+
*args: Any,
|
|
8
8
|
type_: Optional[str] = None,
|
|
9
9
|
message: Optional[str] = None,
|
|
10
10
|
traceback: Optional[str] = None,
|
|
@@ -23,17 +23,17 @@ class AppBaseException(Exception):
|
|
|
23
23
|
self.traceback = traceback
|
|
24
24
|
|
|
25
25
|
# (Optional) make pickling round-trip the extra fields explicitly
|
|
26
|
-
def __reduce__(self):
|
|
26
|
+
def __reduce__(self): # type: ignore
|
|
27
27
|
# Reconstruct with message-only (what Exception expects) and restore extras via state
|
|
28
28
|
return (
|
|
29
29
|
self.__class__,
|
|
30
30
|
(self.message,),
|
|
31
31
|
{"type": self.type, "traceback": self.traceback},
|
|
32
|
-
)
|
|
32
|
+
) # type: ignore
|
|
33
33
|
|
|
34
|
-
def __setstate__(self, state):
|
|
35
|
-
for k, v in state.items():
|
|
36
|
-
setattr(self, k, v)
|
|
34
|
+
def __setstate__(self, state): # type: ignore
|
|
35
|
+
for k, v in state.items(): # type: ignore
|
|
36
|
+
setattr(self, k, v) # type: ignore
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class ApplicationException(AppBaseException):
|
clerk/gui_automation/client.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Dict, List, Optional
|
|
1
|
+
from typing import Any, Dict, List, Optional, Type
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
from clerk.base import BaseClerk
|
|
@@ -16,7 +16,7 @@ from clerk.models.ui_operator import UiOperatorTask
|
|
|
16
16
|
|
|
17
17
|
class RPAClerk(BaseClerk):
|
|
18
18
|
|
|
19
|
-
root_endpoint
|
|
19
|
+
root_endpoint = "/gui_automation"
|
|
20
20
|
|
|
21
21
|
def allocate_remote_device(self, group_name: str, run_id: str):
|
|
22
22
|
endpoint = "/remote_device/allocate"
|
|
@@ -24,7 +24,7 @@ class RPAClerk(BaseClerk):
|
|
|
24
24
|
endpoint=endpoint, json={"group_name": group_name, "run_id": run_id}
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
-
if res.data[0] is None:
|
|
27
|
+
if res.data[0] is None: # type: ignore
|
|
28
28
|
raise NoClientsAvailable()
|
|
29
29
|
|
|
30
30
|
return RemoteDevice(**res.data[0])
|
|
@@ -40,14 +40,14 @@ class RPAClerk(BaseClerk):
|
|
|
40
40
|
json={"id": remote_device.id, "name": remote_device.name, "run_id": run_id},
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
def get_coordinates(self, payload: Dict) -> Coords:
|
|
43
|
+
def get_coordinates(self, payload: Dict[str, Any]) -> Coords:
|
|
44
44
|
endpoint = "/action_model/get_coordinates"
|
|
45
45
|
res = self.post_request(endpoint=endpoint, json=payload)
|
|
46
|
-
if res.data[0] is None:
|
|
46
|
+
if res.data[0] is None: # type: ignore
|
|
47
47
|
raise RuntimeError("No coordinates found in the response.")
|
|
48
48
|
return Coords(**res.data[0])
|
|
49
49
|
|
|
50
|
-
def create_ui_operator_task(self, payload: Dict) -> UiOperatorTask:
|
|
50
|
+
def create_ui_operator_task(self, payload: Dict[str, Any]) -> UiOperatorTask:
|
|
51
51
|
endpoint = "/ui_operator"
|
|
52
52
|
res = self.post_request(endpoint=endpoint, json=payload)
|
|
53
53
|
return UiOperatorTask(**res.data[0])
|
|
@@ -59,7 +59,7 @@ class RPAClerk(BaseClerk):
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
class GUIVisionClerk(BaseClerk):
|
|
62
|
-
root_endpoint
|
|
62
|
+
root_endpoint = "/gui_automation/vision"
|
|
63
63
|
|
|
64
64
|
def find_target(self, screen_b64: str, use_ocr: bool, target_prompt: str):
|
|
65
65
|
endpoint = "/find_target"
|
|
@@ -89,8 +89,12 @@ class GUIVisionClerk(BaseClerk):
|
|
|
89
89
|
return BaseState(**res.data[0])
|
|
90
90
|
|
|
91
91
|
def answer(
|
|
92
|
-
self,
|
|
93
|
-
|
|
92
|
+
self,
|
|
93
|
+
screen_b64: str,
|
|
94
|
+
use_ocr: bool,
|
|
95
|
+
question: str,
|
|
96
|
+
output_model: Type[BaseModel],
|
|
97
|
+
) -> BaseModel:
|
|
94
98
|
endpoint = "/answer"
|
|
95
99
|
res = self.post_request(
|
|
96
100
|
endpoint=endpoint,
|
|
@@ -102,7 +106,7 @@ class GUIVisionClerk(BaseClerk):
|
|
|
102
106
|
},
|
|
103
107
|
)
|
|
104
108
|
|
|
105
|
-
return output_model(**res.data[0])
|
|
109
|
+
return output_model.model_validate(**res.data[0])
|
|
106
110
|
|
|
107
111
|
def classify_state(
|
|
108
112
|
self, screen_b64: str, use_ocr: bool, possible_states: List[Dict[str, str]]
|
|
@@ -136,12 +140,12 @@ class GUIVisionClerk(BaseClerk):
|
|
|
136
140
|
|
|
137
141
|
|
|
138
142
|
class CourseCorrectorClerk(BaseClerk):
|
|
139
|
-
root_endpoint
|
|
143
|
+
root_endpoint = "/gui_automation/course_correction"
|
|
140
144
|
|
|
141
145
|
def get_corrective_actions(
|
|
142
146
|
self,
|
|
143
147
|
screen_b64: str,
|
|
144
|
-
use_ocr:
|
|
148
|
+
use_ocr: bool,
|
|
145
149
|
goal: str,
|
|
146
150
|
custom_instructions: Optional[str] = None,
|
|
147
151
|
) -> ActionString:
|
|
@@ -21,7 +21,7 @@ from .model import PerformActionResponse, ActionStates
|
|
|
21
21
|
from .exception import PerformActionException, GetScreenError
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
async def _perform_action_ws(payload: Dict) -> PerformActionResponse:
|
|
24
|
+
async def _perform_action_ws(payload: Dict[str, Any]) -> PerformActionResponse:
|
|
25
25
|
"""Perform an action over a WebSocket connection.
|
|
26
26
|
|
|
27
27
|
Args:
|
|
@@ -65,7 +65,7 @@ async def _get_screen_async() -> str:
|
|
|
65
65
|
This function sends a request to perform a screenshot action over a WebSocket connection
|
|
66
66
|
and returns the base64 encoded image of the screen captured.
|
|
67
67
|
"""
|
|
68
|
-
payload = {
|
|
68
|
+
payload: Dict[str, Any] = {
|
|
69
69
|
"proc_inst_id": os.getenv("_run_id"),
|
|
70
70
|
"client_name": os.getenv("REMOTE_DEVICE_NAME"),
|
|
71
71
|
"headless": True,
|
|
@@ -131,7 +131,7 @@ async def _perform_action_async(
|
|
|
131
131
|
Raises:
|
|
132
132
|
PerformActionException: If the action fails with an error message.
|
|
133
133
|
"""
|
|
134
|
-
req_payload: Dict = {
|
|
134
|
+
req_payload: Dict[str, Any] = {
|
|
135
135
|
"proc_inst_id": os.getenv("_run_id"),
|
|
136
136
|
"client_name": os.getenv("REMOTE_DEVICE_NAME"),
|
|
137
137
|
"headless": (
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
from typing import Any, List, Literal, Optional, Union
|
|
1
|
+
from typing import Any, List, Literal, Optional, TypeAlias, Union
|
|
2
2
|
from pydantic import BaseModel, Field
|
|
3
3
|
from enum import Enum
|
|
4
4
|
|
|
5
|
+
from clerk.gui_automation.ui_actions.base import ActionTypes
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
|
|
8
|
+
# ActionTypes = Literal[
|
|
9
|
+
# "left_click",
|
|
10
|
+
# "right_click",
|
|
11
|
+
# "middle_click",
|
|
12
|
+
# "double_click",
|
|
13
|
+
# "send_keys",
|
|
14
|
+
# "press_keys",
|
|
15
|
+
# "hot_keys",
|
|
16
|
+
# "paste_text",
|
|
17
|
+
# "get_text",
|
|
18
|
+
# "scroll",
|
|
19
|
+
# ]
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
class ActionStates(Enum):
|
|
@@ -77,6 +79,7 @@ class WindowExecutePayload(BaseModel):
|
|
|
77
79
|
"close_window",
|
|
78
80
|
"activate_window",
|
|
79
81
|
]
|
|
82
|
+
|
|
80
83
|
window_name: str
|
|
81
84
|
timeout: int = Field(default=10)
|
|
82
85
|
|
|
@@ -79,7 +79,7 @@ def gui_automation(
|
|
|
79
79
|
• Passes control to the wrapped function,
|
|
80
80
|
• Cleans everything up afterwards.
|
|
81
81
|
"""
|
|
82
|
-
group_name: str = os.getenv("REMOTE_DEVICE_GROUP")
|
|
82
|
+
group_name: str | None = os.getenv("REMOTE_DEVICE_GROUP")
|
|
83
83
|
if not group_name:
|
|
84
84
|
raise ValueError("REMOTE_DEVICE_GROUP environmental variable is required.")
|
|
85
85
|
|
|
@@ -45,7 +45,7 @@ class File(BaseModel):
|
|
|
45
45
|
|
|
46
46
|
@field_validator("content", mode="before")
|
|
47
47
|
@classmethod
|
|
48
|
-
def convert_to_bytes(cls, v) -> bytes:
|
|
48
|
+
def convert_to_bytes(cls, v: str | bytes) -> bytes:
|
|
49
49
|
if isinstance(v, str):
|
|
50
50
|
from base64 import b64decode
|
|
51
51
|
|
|
@@ -75,7 +75,7 @@ class LeftClick(BaseAction):
|
|
|
75
75
|
LeftClick(target="Suche").above("Kalender").do()
|
|
76
76
|
"""
|
|
77
77
|
|
|
78
|
-
action_type
|
|
78
|
+
action_type = "left_click"
|
|
79
79
|
|
|
80
80
|
@backoff.on_exception(
|
|
81
81
|
backoff.expo,
|
|
@@ -100,7 +100,7 @@ class LeftClick(BaseAction):
|
|
|
100
100
|
|
|
101
101
|
@property
|
|
102
102
|
def actionable_string(self):
|
|
103
|
-
return f"LeftClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
103
|
+
return f"LeftClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}').do()"
|
|
104
104
|
|
|
105
105
|
|
|
106
106
|
class RightClick(BaseAction):
|
|
@@ -118,7 +118,7 @@ class RightClick(BaseAction):
|
|
|
118
118
|
RightClick(target="Suche").above("Kalender").do()
|
|
119
119
|
"""
|
|
120
120
|
|
|
121
|
-
action_type
|
|
121
|
+
action_type = "right_click"
|
|
122
122
|
|
|
123
123
|
@backoff.on_exception(
|
|
124
124
|
backoff.expo,
|
|
@@ -143,7 +143,7 @@ class RightClick(BaseAction):
|
|
|
143
143
|
|
|
144
144
|
@property
|
|
145
145
|
def actionable_string(self):
|
|
146
|
-
return f"RightClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
146
|
+
return f"RightClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}').do()"
|
|
147
147
|
|
|
148
148
|
|
|
149
149
|
class MiddleClickAction(BaseAction):
|
|
@@ -161,7 +161,7 @@ class MiddleClickAction(BaseAction):
|
|
|
161
161
|
MiddleClickAction(target="Suche").above("Kalender").do()
|
|
162
162
|
"""
|
|
163
163
|
|
|
164
|
-
action_type
|
|
164
|
+
action_type = "middle_click"
|
|
165
165
|
|
|
166
166
|
@backoff.on_exception(
|
|
167
167
|
backoff.expo,
|
|
@@ -186,7 +186,7 @@ class MiddleClickAction(BaseAction):
|
|
|
186
186
|
|
|
187
187
|
@property
|
|
188
188
|
def actionable_string(self):
|
|
189
|
-
return f"MiddleClickAction(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
189
|
+
return f"MiddleClickAction(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}').do()"
|
|
190
190
|
|
|
191
191
|
|
|
192
192
|
class DoubleClick(BaseAction):
|
|
@@ -204,7 +204,7 @@ class DoubleClick(BaseAction):
|
|
|
204
204
|
DoubleClick(target="Suche").above("Kalender").do()
|
|
205
205
|
"""
|
|
206
206
|
|
|
207
|
-
action_type
|
|
207
|
+
action_type = "double_click"
|
|
208
208
|
|
|
209
209
|
@backoff.on_exception(
|
|
210
210
|
backoff.expo,
|
|
@@ -229,7 +229,7 @@ class DoubleClick(BaseAction):
|
|
|
229
229
|
|
|
230
230
|
@property
|
|
231
231
|
def actionable_string(self):
|
|
232
|
-
return f"DoubleClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
232
|
+
return f"DoubleClick(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}').do()"
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
class Scroll(BaseAction):
|
|
@@ -249,7 +249,7 @@ class Scroll(BaseAction):
|
|
|
249
249
|
DoubleClick(target="Suche").above("Kalender").do()
|
|
250
250
|
"""
|
|
251
251
|
|
|
252
|
-
action_type
|
|
252
|
+
action_type = "scroll"
|
|
253
253
|
clicks: int
|
|
254
254
|
click_coords: List[int] = Field(default=[])
|
|
255
255
|
|
|
@@ -333,7 +333,7 @@ class SendKeys(BaseAction):
|
|
|
333
333
|
|
|
334
334
|
@property
|
|
335
335
|
def actionable_string(self):
|
|
336
|
-
return f"SendKeys(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
336
|
+
return f"SendKeys(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}', keys='{self.keys}').do()"
|
|
337
337
|
|
|
338
338
|
|
|
339
339
|
class PressKeys(BaseAction):
|
|
@@ -353,7 +353,7 @@ class PressKeys(BaseAction):
|
|
|
353
353
|
PressKeys(keys='ctrl+shift+esc').do()
|
|
354
354
|
"""
|
|
355
355
|
|
|
356
|
-
action_type
|
|
356
|
+
action_type = "press_keys"
|
|
357
357
|
keys: str
|
|
358
358
|
|
|
359
359
|
def do(self):
|
|
@@ -366,7 +366,7 @@ class PressKeys(BaseAction):
|
|
|
366
366
|
|
|
367
367
|
@property
|
|
368
368
|
def actionable_string(self):
|
|
369
|
-
return f"PressKeys(action_type='{self.action_type}', target='{self.target}', anchor='{self.
|
|
369
|
+
return f"PressKeys(action_type='{self.action_type}', target='{self.target}', anchor='{self.anchors}', keys='{self.keys}').do()"
|
|
370
370
|
|
|
371
371
|
|
|
372
372
|
class WaitFor(BaseAction):
|
|
@@ -385,7 +385,7 @@ class WaitFor(BaseAction):
|
|
|
385
385
|
WaitFor("element").do(timeout=60)
|
|
386
386
|
"""
|
|
387
387
|
|
|
388
|
-
action_type
|
|
388
|
+
action_type = "wait_for"
|
|
389
389
|
retry_timeout: float = 0.5
|
|
390
390
|
is_awaited: bool = True
|
|
391
391
|
|
|
@@ -450,7 +450,7 @@ class OpenApplication(BaseAction):
|
|
|
450
450
|
OpenApplication(app_path="/path/to/application.exe", app_window_name="Application Window").do()
|
|
451
451
|
"""
|
|
452
452
|
|
|
453
|
-
action_type
|
|
453
|
+
action_type = "open_app"
|
|
454
454
|
app_path: str = Field(description="Absolute path of the application")
|
|
455
455
|
app_window_name: str = Field(
|
|
456
456
|
description="Name of the application window once open. Wildcard logic enabled."
|
|
@@ -479,7 +479,7 @@ class ForceCloseApplication(BaseAction):
|
|
|
479
479
|
Executes the action to force close the application by creating and performing an ApplicationExecutePayload with the specified process name.
|
|
480
480
|
"""
|
|
481
481
|
|
|
482
|
-
action_type
|
|
482
|
+
action_type = "force_close_app"
|
|
483
483
|
process_name: str = Field(
|
|
484
484
|
description="Process name from task manager. Example: process.exe"
|
|
485
485
|
)
|
|
@@ -509,7 +509,7 @@ class SaveFiles(BaseAction):
|
|
|
509
509
|
SaveFiles(save_location="/path/to/", files=["/path/to/file_1", "/path/to/file_2"]).do()
|
|
510
510
|
"""
|
|
511
511
|
|
|
512
|
-
action_type
|
|
512
|
+
action_type = "save_files"
|
|
513
513
|
save_location: str
|
|
514
514
|
files: Union[List[str], List[FileDetails]]
|
|
515
515
|
|
|
@@ -580,7 +580,7 @@ class GetFile(BaseAction):
|
|
|
580
580
|
GetFile(file_location="/path/to/file_1").do()
|
|
581
581
|
"""
|
|
582
582
|
|
|
583
|
-
action_type
|
|
583
|
+
action_type = "get_file"
|
|
584
584
|
file_location: str
|
|
585
585
|
|
|
586
586
|
def do(self) -> File:
|
|
@@ -605,7 +605,7 @@ class MaximizeWindow(BaseAction):
|
|
|
605
605
|
MaximizeWindow(window_name="MyWindow").do()
|
|
606
606
|
"""
|
|
607
607
|
|
|
608
|
-
action_type
|
|
608
|
+
action_type = "maximize_window"
|
|
609
609
|
window_name: str
|
|
610
610
|
|
|
611
611
|
def do(self, timeout: int = 10):
|
|
@@ -630,7 +630,7 @@ class MinimizeWindow(BaseAction):
|
|
|
630
630
|
MinimizeWindow(window_name="MyWindow").do()
|
|
631
631
|
"""
|
|
632
632
|
|
|
633
|
-
action_type
|
|
633
|
+
action_type = "minimize_window"
|
|
634
634
|
window_name: str
|
|
635
635
|
|
|
636
636
|
def do(self, timeout: int = 10):
|
|
@@ -655,7 +655,7 @@ class CloseWindow(BaseAction):
|
|
|
655
655
|
CloseWindow(window_name="MyWindow").do()
|
|
656
656
|
"""
|
|
657
657
|
|
|
658
|
-
action_type
|
|
658
|
+
action_type = "close_window"
|
|
659
659
|
window_name: str
|
|
660
660
|
|
|
661
661
|
def do(self, timeout: int = 10):
|
|
@@ -680,7 +680,7 @@ class ActivateWindow(BaseAction):
|
|
|
680
680
|
ActivateWindow(window_name="MyWindow").do()
|
|
681
681
|
"""
|
|
682
682
|
|
|
683
|
-
action_type
|
|
683
|
+
action_type = "activate_window"
|
|
684
684
|
window_name: str
|
|
685
685
|
|
|
686
686
|
def do(self, timeout: int = 10):
|
|
@@ -709,7 +709,7 @@ class GetText(BaseAction):
|
|
|
709
709
|
|
|
710
710
|
"""
|
|
711
711
|
|
|
712
|
-
action_type
|
|
712
|
+
action_type = "get_text"
|
|
713
713
|
|
|
714
714
|
@backoff.on_exception(
|
|
715
715
|
backoff.expo,
|
|
@@ -752,7 +752,7 @@ class PasteText(BaseAction):
|
|
|
752
752
|
|
|
753
753
|
"""
|
|
754
754
|
|
|
755
|
-
action_type
|
|
755
|
+
action_type = "paste_text"
|
|
756
756
|
keys: Union[str, List[str]]
|
|
757
757
|
followed_by: Optional[str] = Field(default=None)
|
|
758
758
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Literal, Self, Union, List, Optional
|
|
1
|
+
from typing import Literal, Self, TypeAlias, Union, List, Optional
|
|
2
2
|
from pydantic import BaseModel, Field, model_validator
|
|
3
3
|
from ..client_actor import get_screen
|
|
4
4
|
from ..exceptions.modality.exc import TargetModalityError
|
|
@@ -24,12 +24,13 @@ def to_full_img_path(img: Union[str, ImageB64]) -> str:
|
|
|
24
24
|
return os.path.join(TARGET_IMAGES_PATH, img)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
ActionTypes = Literal[
|
|
27
|
+
ActionTypes: TypeAlias = Literal[
|
|
28
28
|
"left_click",
|
|
29
29
|
"right_click",
|
|
30
30
|
"middle_click",
|
|
31
31
|
"double_click",
|
|
32
32
|
"send_keys",
|
|
33
|
+
"hot_keys",
|
|
33
34
|
"press_keys",
|
|
34
35
|
"wait_for",
|
|
35
36
|
"open_app",
|
|
@@ -130,6 +131,8 @@ class BaseAction(BaseModel):
|
|
|
130
131
|
return [xcenter, ycenter]
|
|
131
132
|
|
|
132
133
|
def _prepare_payload(self):
|
|
134
|
+
if not self.target:
|
|
135
|
+
raise ValueError("target cannot be None.")
|
|
133
136
|
payload: Screenshot = Screenshot(
|
|
134
137
|
screen_b64=ImageB64(value=get_screen()),
|
|
135
138
|
target=self.target,
|
|
@@ -115,7 +115,7 @@ class Vision(BaseModel):
|
|
|
115
115
|
The current state of the GUI (BaseState or a subclass of BaseState)
|
|
116
116
|
"""
|
|
117
117
|
screen_b64 = get_screen()
|
|
118
|
-
state = self.verify_state(
|
|
118
|
+
state = self.clerk_client.verify_state(
|
|
119
119
|
screen_b64,
|
|
120
120
|
self.use_ocr,
|
|
121
121
|
possible_states,
|
|
@@ -160,7 +160,7 @@ class Vision(BaseModel):
|
|
|
160
160
|
screen_b64, self.use_ocr, possible_states
|
|
161
161
|
)
|
|
162
162
|
# if output_model is provided, return the model, otherwise return the id and description of the default model
|
|
163
|
-
if output_model is not None:
|
|
163
|
+
if output_model is not None: # type: ignore
|
|
164
164
|
return state
|
|
165
165
|
assert isinstance(state, BaseState)
|
|
166
166
|
return state.id, state.description
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from pydantic import BaseModel, field_validator
|
|
2
|
-
from typing import List, Dict, Optional
|
|
1
|
+
from pydantic import BaseModel, field_validator
|
|
2
|
+
from typing import Any, List, Dict, Optional
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class BaseState(BaseModel):
|
|
@@ -21,7 +21,7 @@ class BaseState(BaseModel):
|
|
|
21
21
|
|
|
22
22
|
id: str
|
|
23
23
|
description: str
|
|
24
|
-
screenshots: List = []
|
|
24
|
+
screenshots: List[Dict[str, str]] = []
|
|
25
25
|
|
|
26
26
|
def add_screenshot(self, bucket_name: str, file_name: str):
|
|
27
27
|
self.screenshots.append({"bucket_name": bucket_name, "file_name": file_name})
|
|
@@ -137,7 +137,7 @@ class TargetWithAnchor(BaseModel):
|
|
|
137
137
|
|
|
138
138
|
@field_validator("target", mode="before")
|
|
139
139
|
@classmethod
|
|
140
|
-
def retain_one_word(cls, v):
|
|
140
|
+
def retain_one_word(cls, v: str):
|
|
141
141
|
return v.split(" ")[-1]
|
|
142
142
|
|
|
143
143
|
|
|
@@ -174,7 +174,7 @@ class ActionString(BaseModel):
|
|
|
174
174
|
|
|
175
175
|
@field_validator("action_string", mode="before")
|
|
176
176
|
@classmethod
|
|
177
|
-
def ensure_format(cls, v):
|
|
177
|
+
def ensure_format(cls, v: Any):
|
|
178
178
|
if not isinstance(v, str):
|
|
179
179
|
raise ValueError("Action string must be a string")
|
|
180
180
|
if not v.startswith("LeftClick") and not v.startswith("NoAction"):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
from pydantic import BaseModel, field_validator
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
from pydantic import BaseModel, field_validator
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class ActionString(BaseModel):
|
|
@@ -24,7 +24,7 @@ class ActionString(BaseModel):
|
|
|
24
24
|
|
|
25
25
|
@field_validator("action_string", mode="before")
|
|
26
26
|
@classmethod
|
|
27
|
-
def ensure_format(cls, v):
|
|
27
|
+
def ensure_format(cls, v: Any):
|
|
28
28
|
if not isinstance(v, str):
|
|
29
29
|
raise ValueError("Action string must be a string")
|
|
30
30
|
if not v.endswith(".do()") and not v.startswith("NoAction"):
|
|
@@ -32,7 +32,7 @@ class ActionString(BaseModel):
|
|
|
32
32
|
return v
|
|
33
33
|
|
|
34
34
|
@field_validator("interrupt_process", mode="before")
|
|
35
|
-
def convert_to_bool(cls, v):
|
|
35
|
+
def convert_to_bool(cls, v: str | bool | None):
|
|
36
36
|
if v is None:
|
|
37
37
|
return False
|
|
38
38
|
elif isinstance(v, str):
|
clerk/models/document.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import datetime
|
|
2
|
-
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import mimetypes
|
|
3
|
+
import os
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
3
5
|
from pydantic import BaseModel
|
|
4
6
|
|
|
5
7
|
from clerk.models.document_statuses import DocumentStatuses
|
|
8
|
+
from clerk.models.file import ParsedFile
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class Document(BaseModel):
|
|
@@ -14,7 +17,65 @@ class Document(BaseModel):
|
|
|
14
17
|
message_subject: Optional[str] = None
|
|
15
18
|
message_content: Optional[str] = None
|
|
16
19
|
message_html: Optional[str] = None
|
|
17
|
-
structured_data: Optional[Dict] = None
|
|
20
|
+
structured_data: Optional[Dict[str, Any]] = None
|
|
18
21
|
status: DocumentStatuses
|
|
19
22
|
created_at: datetime
|
|
20
23
|
updated_at: datetime
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class UploadDocumentRequest(BaseModel):
|
|
27
|
+
project_id: str
|
|
28
|
+
message_subject: Optional[str] = None
|
|
29
|
+
message_content: Optional[str] = None
|
|
30
|
+
files: List[str | ParsedFile] = []
|
|
31
|
+
|
|
32
|
+
def _define_files(self):
|
|
33
|
+
formatted_files: List[
|
|
34
|
+
tuple[
|
|
35
|
+
str,
|
|
36
|
+
tuple[
|
|
37
|
+
str,
|
|
38
|
+
bytes,
|
|
39
|
+
str | None,
|
|
40
|
+
],
|
|
41
|
+
]
|
|
42
|
+
] = []
|
|
43
|
+
|
|
44
|
+
for file in self.files:
|
|
45
|
+
if isinstance(file, str):
|
|
46
|
+
if os.path.exists(file):
|
|
47
|
+
tmp = (
|
|
48
|
+
"files",
|
|
49
|
+
(
|
|
50
|
+
os.path.basename(file).replace(" ", "_"),
|
|
51
|
+
open(file, "rb").read(),
|
|
52
|
+
mimetypes.guess_type(file)[0],
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
else:
|
|
57
|
+
raise FileExistsError(file)
|
|
58
|
+
else:
|
|
59
|
+
tmp = (
|
|
60
|
+
"files",
|
|
61
|
+
(
|
|
62
|
+
file.name,
|
|
63
|
+
file.decoded_content,
|
|
64
|
+
file.mimetype,
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
formatted_files.append(tmp)
|
|
68
|
+
|
|
69
|
+
return formatted_files
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def data(self) -> Dict[str, Any]:
|
|
73
|
+
return dict(
|
|
74
|
+
project_id=self.project_id,
|
|
75
|
+
message_subject=self.message_subject,
|
|
76
|
+
mesasge_content=self.message_content,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def files_(self):
|
|
81
|
+
return self._define_files()
|
clerk/models/file.py
CHANGED
|
@@ -18,8 +18,10 @@ class ParsedFile(BaseModel):
|
|
|
18
18
|
|
|
19
19
|
class UploadFile(BaseModel):
|
|
20
20
|
name: str
|
|
21
|
-
mimetype: str
|
|
21
|
+
mimetype: str | None
|
|
22
22
|
content: bytes
|
|
23
23
|
|
|
24
|
-
def to_multipart_format(
|
|
24
|
+
def to_multipart_format(
|
|
25
|
+
self, key: str = "files"
|
|
26
|
+
) -> Tuple[str, Tuple[str, bytes, str | None]]:
|
|
25
27
|
return (key, (self.name, self.content, self.mimetype))
|
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
clerk/__init__.py,sha256=LWpbImG7352mUJYC1tRm_zsn5rnt4sFl5ldoq5f0dlo,26
|
|
2
|
-
clerk/base.py,sha256=
|
|
3
|
-
clerk/client.py,sha256=
|
|
4
|
-
clerk/decorator/__init__.py,sha256=
|
|
5
|
-
clerk/decorator/models.py,sha256=
|
|
6
|
-
clerk/decorator/task_decorator.py,sha256=
|
|
2
|
+
clerk/base.py,sha256=S1RKc2pBw2FPlVjefJzsNtyTDPB0UG46C2K_QVV1opA,4008
|
|
3
|
+
clerk/client.py,sha256=cgDOO9fRfJAoV5_r6PCoPWoAY0OwoeEMT3cEkzUSZOI,1612
|
|
4
|
+
clerk/decorator/__init__.py,sha256=yGGcS17VsZ7cZ-hVGCm3I3vGDJMiJIAqmDGzriIi0DI,65
|
|
5
|
+
clerk/decorator/models.py,sha256=PiAugPvX1c6BQBWtfhyh5k9Uau2OJNDIx7T1TLz7ZFY,409
|
|
6
|
+
clerk/decorator/task_decorator.py,sha256=H8caRvNvvl-IRwyREP66gBGVM-SpQJ1W7oAFImO-6Jw,3769
|
|
7
7
|
clerk/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
clerk/exceptions/exceptions.py,sha256=
|
|
8
|
+
clerk/exceptions/exceptions.py,sha256=gSCma06b6W6c0NrA2rhzd5YjFhZGa6caShX07lo-_3E,1291
|
|
9
9
|
clerk/exceptions/remote_device.py,sha256=R0Vfmk8ejibEFeV29A8Vqst2YA6yxdqEX9lP5wWubgM,134
|
|
10
10
|
clerk/gui_automation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
clerk/gui_automation/client.py,sha256=
|
|
11
|
+
clerk/gui_automation/client.py,sha256=zxZ2QgxXvOEenXz2LpZv9vySJRbVnqY5f1lYr4bTQ9E,5000
|
|
12
12
|
clerk/gui_automation/action_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
clerk/gui_automation/action_model/model.py,sha256=
|
|
13
|
+
clerk/gui_automation/action_model/model.py,sha256=yzaCyEMOH3YMkPBf6IwUMuu69-xyf78HzmthiewgWQY,3811
|
|
14
14
|
clerk/gui_automation/action_model/utils.py,sha256=xzFxgN-bTK6HKGS7J-esQZ-ePj_yG72T-2ZVhcWvKjw,798
|
|
15
15
|
clerk/gui_automation/client_actor/__init__.py,sha256=SVuL6-oo1Xc0oJkjMKrO6mJwpPGjrCLKhDV6r2Abtf8,66
|
|
16
|
-
clerk/gui_automation/client_actor/client_actor.py,sha256=
|
|
16
|
+
clerk/gui_automation/client_actor/client_actor.py,sha256=RT5WnvrM37pLpoDd_WZg8sSjBuugqMW_eDLTEkL7kWc,5117
|
|
17
17
|
clerk/gui_automation/client_actor/exception.py,sha256=zdnImHZ88yf52Xq3aMHivEU3aJg-r2c-r8x8XZnI3ic,407
|
|
18
|
-
clerk/gui_automation/client_actor/model.py,sha256=
|
|
18
|
+
clerk/gui_automation/client_actor/model.py,sha256=B6tYQB0ngY3oM6pWIoJLTi_H9U-hTgQqal7b7rSWkd8,6433
|
|
19
19
|
clerk/gui_automation/decorators/__init__.py,sha256=OCgXStEumscgT-RyVy5OKS7ml1w9y-lEnjCVnxuRnQs,43
|
|
20
|
-
clerk/gui_automation/decorators/gui_automation.py,sha256=
|
|
20
|
+
clerk/gui_automation/decorators/gui_automation.py,sha256=jqzN_iqIq2KvjUU-JoYnUSOf-mst31EKCk8zdMFzGQM,5357
|
|
21
21
|
clerk/gui_automation/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
clerk/gui_automation/exceptions/agent_manager.py,sha256=KFWFWQ7X_8Z9XG__SMzb1jKI3yNoVTPJAXzW5O-fSXc,101
|
|
23
23
|
clerk/gui_automation/exceptions/websocket.py,sha256=-MdwSwlf1hbnu55aDgk3L1znkTZ6xJS6po5VpEGD9ck,117
|
|
24
24
|
clerk/gui_automation/exceptions/modality/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
25
|
clerk/gui_automation/exceptions/modality/exc.py,sha256=P-dMuCTyVZYD3pbGpCf_1SYEgaETn13c51pmfbsXr5k,1436
|
|
26
26
|
clerk/gui_automation/ui_actions/__init__.py,sha256=-EDQ5375HXrvG3sfFY7zOPC405YcBL6xXRACm2p-YyI,23
|
|
27
|
-
clerk/gui_automation/ui_actions/actions.py,sha256=
|
|
28
|
-
clerk/gui_automation/ui_actions/base.py,sha256=
|
|
27
|
+
clerk/gui_automation/ui_actions/actions.py,sha256=qFustr0Wr81Bq6tS9sPqqFMC5zwG5-XmjKy1kFwjSKc,26914
|
|
28
|
+
clerk/gui_automation/ui_actions/base.py,sha256=ymYWZnleywyI2DeaAb_HuDxgoSgfgw0zjXyQGp4Nvqo,7351
|
|
29
29
|
clerk/gui_automation/ui_actions/support.py,sha256=Ulb8DBfwnrBMaYoMLDgldEy9V--NDUSdhIYXpuODZoU,5772
|
|
30
30
|
clerk/gui_automation/ui_state_inspector/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
|
-
clerk/gui_automation/ui_state_inspector/gui_vision.py,sha256=
|
|
32
|
-
clerk/gui_automation/ui_state_inspector/models.py,sha256=
|
|
31
|
+
clerk/gui_automation/ui_state_inspector/gui_vision.py,sha256=Pk5nuFZnp_zNbqSOtndSmgqb6PLeADJfnC-eRIJMDZk,7736
|
|
32
|
+
clerk/gui_automation/ui_state_inspector/models.py,sha256=ieri9ht2X694V5snYShj_9LHX8AtdCzSw5mCsCSLbj0,5705
|
|
33
33
|
clerk/gui_automation/ui_state_machine/__init__.py,sha256=bTPZsPJkDLCwP2mdtBj4fU7C7ekOh0b-VPRKFEV3bPo,301
|
|
34
34
|
clerk/gui_automation/ui_state_machine/ai_recovery.py,sha256=3_Gu_RPxta4eXmXWH3WA31c15sJL-dk1m1H2bOFV7so,3772
|
|
35
35
|
clerk/gui_automation/ui_state_machine/decorators.py,sha256=gBOpIusjsXlA7FEiszDCFKTS6vXx3LBNMz_SQJNkMWg,2134
|
|
36
36
|
clerk/gui_automation/ui_state_machine/exceptions.py,sha256=9KWg20dnCssMdMu632E0nP5vkndgYNI4cDCDW-vMkQA,1436
|
|
37
|
-
clerk/gui_automation/ui_state_machine/models.py,sha256=
|
|
37
|
+
clerk/gui_automation/ui_state_machine/models.py,sha256=oNmfHtjqgRkUAxPnQ8R5-IR-K_FCeg3NU6aqjVSnThI,1407
|
|
38
38
|
clerk/gui_automation/ui_state_machine/state_machine.py,sha256=u2wJqu5WxmZHkzlIHTgK_icZUw3yv9nNuZkh9IaqmXI,35622
|
|
39
39
|
clerk/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
-
clerk/models/document.py,sha256=
|
|
40
|
+
clerk/models/document.py,sha256=m9ccAQdy1G-ZgUT-a44TMgIVAp4he-90uYjVPqwgO98,2193
|
|
41
41
|
clerk/models/document_statuses.py,sha256=ytTQhgACs2m22qz51_7Ti0IxzbVyl-fl7uF7CnDEyLA,279
|
|
42
|
-
clerk/models/file.py,sha256=
|
|
42
|
+
clerk/models/file.py,sha256=wfMGoNTsIBFxpPUzOTOkUYZ-FGxXg6n2mZhDCBt6Jbc,733
|
|
43
43
|
clerk/models/remote_device.py,sha256=2jijS-9WWq7y6xIbAaDaPnzZo3-tjp2-dCQvNKP8YSU,109
|
|
44
44
|
clerk/models/response_model.py,sha256=R62daUN1YVOwgnrh_epvFRsQcOwT7R4u97l73egvm-c,232
|
|
45
45
|
clerk/models/ui_operator.py,sha256=mKTJUFZgv7PeEt5oys28HVZxHOJsofmRQOcRpqj0dbU,293
|
|
46
46
|
clerk/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
47
47
|
clerk/utils/logger.py,sha256=vHbp-lUK3W3c5fhyPsp05p9LGyDHj95v8XM_XQ_FlLc,3691
|
|
48
48
|
clerk/utils/save_artifact.py,sha256=94aYkYNVGcSUaSWZmdjiY6Oc-3yCKb2XWCZ56IAXQqk,1158
|
|
49
|
-
clerk_sdk-0.
|
|
50
|
-
clerk_sdk-0.
|
|
51
|
-
clerk_sdk-0.
|
|
52
|
-
clerk_sdk-0.
|
|
53
|
-
clerk_sdk-0.
|
|
49
|
+
clerk_sdk-0.4.1.dist-info/licenses/LICENSE,sha256=GTVQl3vH6ht70wJXKC0yMT8CmXKHxv_YyO_utAgm7EA,1065
|
|
50
|
+
clerk_sdk-0.4.1.dist-info/METADATA,sha256=50SHt0qwDSsCh5X8ew-k-NBccXZdCyrJ75EuNK7Cm5o,3508
|
|
51
|
+
clerk_sdk-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
52
|
+
clerk_sdk-0.4.1.dist-info/top_level.txt,sha256=99eQiU6d05_-f41tmSFanfI_SIJeAdh7u9m3LNSfcv4,6
|
|
53
|
+
clerk_sdk-0.4.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|