optexity 0.1.2__py3-none-any.whl → 0.1.3__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.
- optexity/examples/__init__.py +0 -0
- optexity/examples/add_example.py +88 -0
- optexity/examples/download_pdf_url.py +29 -0
- optexity/examples/extract_price_stockanalysis.py +44 -0
- optexity/examples/file_upload.py +59 -0
- optexity/examples/i94.py +126 -0
- optexity/examples/i94_travel_history.py +126 -0
- optexity/examples/peachstate_medicaid.py +201 -0
- optexity/examples/supabase_login.py +75 -0
- optexity/inference/__init__.py +0 -0
- optexity/inference/agents/__init__.py +0 -0
- optexity/inference/agents/error_handler/__init__.py +0 -0
- optexity/inference/agents/error_handler/error_handler.py +39 -0
- optexity/inference/agents/error_handler/prompt.py +60 -0
- optexity/inference/agents/index_prediction/__init__.py +0 -0
- optexity/inference/agents/index_prediction/action_prediction_locator_axtree.py +45 -0
- optexity/inference/agents/index_prediction/prompt.py +14 -0
- optexity/inference/agents/select_value_prediction/__init__.py +0 -0
- optexity/inference/agents/select_value_prediction/prompt.py +20 -0
- optexity/inference/agents/select_value_prediction/select_value_prediction.py +39 -0
- optexity/inference/agents/two_fa_extraction/__init__.py +0 -0
- optexity/inference/agents/two_fa_extraction/prompt.py +23 -0
- optexity/inference/agents/two_fa_extraction/two_fa_extraction.py +47 -0
- optexity/inference/child_process.py +251 -0
- optexity/inference/core/__init__.py +0 -0
- optexity/inference/core/interaction/__init__.py +0 -0
- optexity/inference/core/interaction/handle_agentic_task.py +79 -0
- optexity/inference/core/interaction/handle_check.py +57 -0
- optexity/inference/core/interaction/handle_click.py +79 -0
- optexity/inference/core/interaction/handle_command.py +261 -0
- optexity/inference/core/interaction/handle_input.py +76 -0
- optexity/inference/core/interaction/handle_keypress.py +16 -0
- optexity/inference/core/interaction/handle_select.py +109 -0
- optexity/inference/core/interaction/handle_select_utils.py +132 -0
- optexity/inference/core/interaction/handle_upload.py +59 -0
- optexity/inference/core/interaction/utils.py +81 -0
- optexity/inference/core/logging.py +406 -0
- optexity/inference/core/run_assertion.py +55 -0
- optexity/inference/core/run_automation.py +463 -0
- optexity/inference/core/run_extraction.py +240 -0
- optexity/inference/core/run_interaction.py +254 -0
- optexity/inference/core/run_python_script.py +20 -0
- optexity/inference/core/run_two_fa.py +120 -0
- optexity/inference/core/two_factor_auth/__init__.py +0 -0
- optexity/inference/infra/__init__.py +0 -0
- optexity/inference/infra/browser.py +455 -0
- optexity/inference/infra/browser_extension.py +20 -0
- optexity/inference/models/__init__.py +22 -0
- optexity/inference/models/gemini.py +113 -0
- optexity/inference/models/human.py +20 -0
- optexity/inference/models/llm_model.py +210 -0
- optexity/inference/run_local.py +200 -0
- optexity/schema/__init__.py +0 -0
- optexity/schema/actions/__init__.py +0 -0
- optexity/schema/actions/assertion_action.py +66 -0
- optexity/schema/actions/extraction_action.py +143 -0
- optexity/schema/actions/interaction_action.py +330 -0
- optexity/schema/actions/misc_action.py +18 -0
- optexity/schema/actions/prompts.py +27 -0
- optexity/schema/actions/two_fa_action.py +24 -0
- optexity/schema/automation.py +432 -0
- optexity/schema/callback.py +16 -0
- optexity/schema/inference.py +87 -0
- optexity/schema/memory.py +100 -0
- optexity/schema/task.py +212 -0
- optexity/schema/token_usage.py +48 -0
- optexity/utils/__init__.py +0 -0
- optexity/utils/settings.py +54 -0
- optexity/utils/utils.py +76 -0
- {optexity-0.1.2.dist-info → optexity-0.1.3.dist-info}/METADATA +1 -1
- optexity-0.1.3.dist-info/RECORD +80 -0
- optexity-0.1.2.dist-info/RECORD +0 -11
- {optexity-0.1.2.dist-info → optexity-0.1.3.dist-info}/WHEEL +0 -0
- {optexity-0.1.2.dist-info → optexity-0.1.3.dist-info}/entry_points.txt +0 -0
- {optexity-0.1.2.dist-info → optexity-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {optexity-0.1.2.dist-info → optexity-0.1.3.dist-info}/top_level.txt +0 -0
optexity/schema/task.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import json
|
|
3
|
+
import string
|
|
4
|
+
import uuid
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from io import BytesIO
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Literal, Optional
|
|
9
|
+
|
|
10
|
+
from PIL import Image
|
|
11
|
+
from pydantic import BaseModel, Field, computed_field, model_validator
|
|
12
|
+
|
|
13
|
+
from optexity.schema.automation import Automation, SecureParameter
|
|
14
|
+
from optexity.schema.memory import ForLoopStatus
|
|
15
|
+
from optexity.schema.token_usage import TokenUsage
|
|
16
|
+
|
|
17
|
+
BASE62 = string.digits + string.ascii_lowercase + string.ascii_uppercase
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def uuid_str_to_base62(uuid_str: str) -> str:
|
|
21
|
+
n = uuid.UUID(uuid_str).int
|
|
22
|
+
out = []
|
|
23
|
+
while n:
|
|
24
|
+
n, r = divmod(n, 62)
|
|
25
|
+
out.append(BASE62[r])
|
|
26
|
+
return "".join(reversed(out))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CallbackUrl(BaseModel):
|
|
30
|
+
url: str
|
|
31
|
+
api_key: str | None = None
|
|
32
|
+
username: str | None = None
|
|
33
|
+
password: str | None = None
|
|
34
|
+
|
|
35
|
+
@model_validator(mode="after")
|
|
36
|
+
def validate_callback_url(self):
|
|
37
|
+
|
|
38
|
+
if self.api_key is not None and (
|
|
39
|
+
self.username is not None or self.password is not None
|
|
40
|
+
):
|
|
41
|
+
raise ValueError(
|
|
42
|
+
"api_key and username/password cannot be used together. Please provide only one of them."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return self
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Task(BaseModel):
|
|
49
|
+
task_id: str
|
|
50
|
+
user_id: str
|
|
51
|
+
recording_id: str
|
|
52
|
+
endpoint_name: str
|
|
53
|
+
automation: Automation
|
|
54
|
+
input_parameters: dict[str, list[str | int | float | bool]]
|
|
55
|
+
secure_parameters: dict[str, list[SecureParameter]]
|
|
56
|
+
unique_parameter_names: list[str]
|
|
57
|
+
unique_parameters: dict[str, list[str]] | None = None
|
|
58
|
+
created_at: datetime
|
|
59
|
+
allocated_at: Optional[datetime] = None
|
|
60
|
+
started_at: Optional[datetime] = None
|
|
61
|
+
completed_at: Optional[datetime] = None
|
|
62
|
+
error: Optional[str] = None
|
|
63
|
+
status: Literal["queued", "allocated", "running", "success", "failed", "cancelled"]
|
|
64
|
+
is_cloud: bool = False
|
|
65
|
+
save_directory: Path = Field(default=Path("/tmp/optexity"))
|
|
66
|
+
use_proxy: bool = False
|
|
67
|
+
|
|
68
|
+
dedup_key: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
69
|
+
retry_count: int = 0
|
|
70
|
+
max_retries: int = 1
|
|
71
|
+
api_key: str
|
|
72
|
+
callback_url: CallbackUrl | None = None
|
|
73
|
+
|
|
74
|
+
class Config:
|
|
75
|
+
json_encoders = {datetime: lambda v: v.isoformat() if v is not None else None}
|
|
76
|
+
|
|
77
|
+
@computed_field
|
|
78
|
+
@property
|
|
79
|
+
def task_directory(self) -> Path:
|
|
80
|
+
return self.save_directory / str(self.task_id)
|
|
81
|
+
|
|
82
|
+
@computed_field
|
|
83
|
+
@property
|
|
84
|
+
def logs_directory(self) -> Path:
|
|
85
|
+
return self.task_directory / "logs"
|
|
86
|
+
|
|
87
|
+
@computed_field
|
|
88
|
+
@property
|
|
89
|
+
def downloads_directory(self) -> Path:
|
|
90
|
+
return self.task_directory / "downloads"
|
|
91
|
+
|
|
92
|
+
@computed_field
|
|
93
|
+
@property
|
|
94
|
+
def log_file_path(self) -> Path:
|
|
95
|
+
return self.logs_directory / "optexity.log"
|
|
96
|
+
|
|
97
|
+
@model_validator(mode="after")
|
|
98
|
+
def validate_unique_parameters(self):
|
|
99
|
+
## TODO: we do not do dedup using secure parameters yet, need to add support for that
|
|
100
|
+
if len(self.unique_parameter_names) > 0:
|
|
101
|
+
self.unique_parameters = {
|
|
102
|
+
unique_parameter_name: self.input_parameters[unique_parameter_name]
|
|
103
|
+
for unique_parameter_name in self.unique_parameter_names
|
|
104
|
+
}
|
|
105
|
+
self.dedup_key = json.dumps(self.unique_parameters, sort_keys=True)
|
|
106
|
+
|
|
107
|
+
for a, b in [
|
|
108
|
+
(self.automation.parameters.input_parameters, self.input_parameters),
|
|
109
|
+
(self.automation.parameters.secure_parameters, self.secure_parameters),
|
|
110
|
+
]:
|
|
111
|
+
if a.keys() != b.keys():
|
|
112
|
+
missing_keys = a.keys() - b.keys()
|
|
113
|
+
extra_keys = b.keys() - a.keys()
|
|
114
|
+
raise ValueError(
|
|
115
|
+
f"Please provide exactly the same {a} as the automation. Missing keys: {missing_keys}, Extra keys: {extra_keys}"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
@model_validator(mode="after")
|
|
121
|
+
def set_dependent_paths(self):
|
|
122
|
+
|
|
123
|
+
self.logs_directory.mkdir(parents=True, exist_ok=True)
|
|
124
|
+
self.downloads_directory.mkdir(parents=True, exist_ok=True)
|
|
125
|
+
self.log_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
126
|
+
|
|
127
|
+
return self
|
|
128
|
+
|
|
129
|
+
def proxy_session_id(
|
|
130
|
+
self, proxy_provider: Literal["oxylabs", "other"] | None
|
|
131
|
+
) -> str | None:
|
|
132
|
+
if not self.use_proxy:
|
|
133
|
+
return None
|
|
134
|
+
if proxy_provider == "oxylabs":
|
|
135
|
+
return uuid_str_to_base62(self.task_id)
|
|
136
|
+
else:
|
|
137
|
+
return "default"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class TaskCreateRequest(BaseModel):
|
|
141
|
+
task_id: str
|
|
142
|
+
recording_id: str
|
|
143
|
+
input_parameters: dict
|
|
144
|
+
unique_parameter_names: list[str]
|
|
145
|
+
created_at: datetime
|
|
146
|
+
|
|
147
|
+
@model_validator(mode="after")
|
|
148
|
+
def must_have_timezone(self):
|
|
149
|
+
if self.created_at.tzinfo is None:
|
|
150
|
+
raise ValueError("created_at must include timezone information")
|
|
151
|
+
|
|
152
|
+
for unique_parameter_name in self.unique_parameter_names:
|
|
153
|
+
if unique_parameter_name not in self.input_parameters:
|
|
154
|
+
raise ValueError(
|
|
155
|
+
f"unique_parameter_name {unique_parameter_name} not found in input_parameters"
|
|
156
|
+
)
|
|
157
|
+
return self
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class TaskStartedRequest(BaseModel):
|
|
161
|
+
task_id: str
|
|
162
|
+
started_at: datetime
|
|
163
|
+
allocated_at: Optional[datetime] = None
|
|
164
|
+
|
|
165
|
+
@model_validator(mode="after")
|
|
166
|
+
def must_have_timezone(self):
|
|
167
|
+
if self.started_at.tzinfo is None:
|
|
168
|
+
raise ValueError("started_at must include timezone information")
|
|
169
|
+
if self.allocated_at is not None and self.allocated_at.tzinfo is None:
|
|
170
|
+
raise ValueError("allocated_at must include timezone information")
|
|
171
|
+
return self
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class TaskCompleteRequest(BaseModel):
|
|
175
|
+
task_id: str
|
|
176
|
+
child_process_id: int
|
|
177
|
+
|
|
178
|
+
status: Literal["success", "failed", "cancelled"]
|
|
179
|
+
error: str | None
|
|
180
|
+
completed_at: datetime
|
|
181
|
+
token_usage: TokenUsage
|
|
182
|
+
|
|
183
|
+
@model_validator(mode="after")
|
|
184
|
+
def must_have_timezone(self):
|
|
185
|
+
if self.completed_at.tzinfo is None:
|
|
186
|
+
raise ValueError("completed_at must include timezone information")
|
|
187
|
+
return self
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class TaskOutputDataRequest(BaseModel):
|
|
191
|
+
task_id: str
|
|
192
|
+
output_data: list[dict]
|
|
193
|
+
final_screenshot: str | None
|
|
194
|
+
for_loop_status: list[list[ForLoopStatus]] | None = None
|
|
195
|
+
|
|
196
|
+
@model_validator(mode="after")
|
|
197
|
+
def must_have_valid_final_screenshot(self):
|
|
198
|
+
if self.final_screenshot is not None and not self.is_valid_base64_image(
|
|
199
|
+
self.final_screenshot
|
|
200
|
+
):
|
|
201
|
+
raise ValueError("final_screenshot must be a valid base64 encoded image")
|
|
202
|
+
return self
|
|
203
|
+
|
|
204
|
+
def is_valid_base64_image(self, data: str) -> bool:
|
|
205
|
+
try:
|
|
206
|
+
# Decode the base64 string
|
|
207
|
+
decoded = base64.b64decode(data, validate=True)
|
|
208
|
+
# Try to open it as an image
|
|
209
|
+
Image.open(BytesIO(decoded))
|
|
210
|
+
return True
|
|
211
|
+
except Exception as e:
|
|
212
|
+
return False
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from pydantic import BaseModel
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TokenUsage(BaseModel):
|
|
5
|
+
input_tokens: int = 0
|
|
6
|
+
output_tokens: int = 0
|
|
7
|
+
tool_use_tokens: int = 0
|
|
8
|
+
thoughts_tokens: int = 0
|
|
9
|
+
total_tokens: int = 0
|
|
10
|
+
calculated_total_tokens: int = 0
|
|
11
|
+
|
|
12
|
+
input_cost: float = 0
|
|
13
|
+
output_cost: float = 0
|
|
14
|
+
tool_use_cost: float = 0
|
|
15
|
+
thoughts_cost: float = 0
|
|
16
|
+
total_cost: float = 0
|
|
17
|
+
|
|
18
|
+
def __add__(self, other: "TokenUsage") -> "TokenUsage":
|
|
19
|
+
return TokenUsage(
|
|
20
|
+
input_tokens=self.input_tokens + other.input_tokens,
|
|
21
|
+
output_tokens=self.output_tokens + other.output_tokens,
|
|
22
|
+
total_tokens=self.total_tokens + other.total_tokens,
|
|
23
|
+
tool_use_tokens=self.tool_use_tokens + other.tool_use_tokens,
|
|
24
|
+
thoughts_tokens=self.thoughts_tokens + other.thoughts_tokens,
|
|
25
|
+
calculated_total_tokens=self.calculated_total_tokens
|
|
26
|
+
+ other.calculated_total_tokens,
|
|
27
|
+
input_cost=self.input_cost + other.input_cost,
|
|
28
|
+
output_cost=self.output_cost + other.output_cost,
|
|
29
|
+
tool_use_cost=self.tool_use_cost + other.tool_use_cost,
|
|
30
|
+
thoughts_cost=self.thoughts_cost + other.thoughts_cost,
|
|
31
|
+
total_cost=self.total_cost + other.total_cost,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def __sub__(self, other: "TokenUsage") -> "TokenUsage":
|
|
35
|
+
return TokenUsage(
|
|
36
|
+
input_tokens=self.input_tokens - other.input_tokens,
|
|
37
|
+
output_tokens=self.output_tokens - other.output_tokens,
|
|
38
|
+
total_tokens=self.total_tokens - other.total_tokens,
|
|
39
|
+
tool_use_tokens=self.tool_use_tokens - other.tool_use_tokens,
|
|
40
|
+
thoughts_tokens=self.thoughts_tokens - other.thoughts_tokens,
|
|
41
|
+
calculated_total_tokens=self.calculated_total_tokens
|
|
42
|
+
- other.calculated_total_tokens,
|
|
43
|
+
input_cost=self.input_cost - other.input_cost,
|
|
44
|
+
output_cost=self.output_cost - other.output_cost,
|
|
45
|
+
tool_use_cost=self.tool_use_cost - other.tool_use_cost,
|
|
46
|
+
thoughts_cost=self.thoughts_cost - other.thoughts_cost,
|
|
47
|
+
total_cost=self.total_cost - other.total_cost,
|
|
48
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
from pydantic import model_validator
|
|
6
|
+
from pydantic_settings import BaseSettings
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
env_path = os.getenv("ENV_PATH")
|
|
11
|
+
if not env_path:
|
|
12
|
+
logger.warning("ENV_PATH is not set, using default values")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Settings(BaseSettings):
|
|
16
|
+
SERVER_URL: str = "https://api.optexity.com"
|
|
17
|
+
HEALTH_ENDPOINT: str = "api/v1/health"
|
|
18
|
+
INFERENCE_ENDPOINT: str = "api/v1/inference"
|
|
19
|
+
ADD_EXAMPLE_ENDPOINT: str = "api/v1/add_example"
|
|
20
|
+
UPDATE_EXAMPLE_ENDPOINT: str = "api/v1/update_example"
|
|
21
|
+
START_TASK_ENDPOINT: str = "api/v1/start_task"
|
|
22
|
+
COMPLETE_TASK_ENDPOINT: str = "api/v1/complete_task"
|
|
23
|
+
SAVE_OUTPUT_DATA_ENDPOINT: str = "api/v1/save_output_data"
|
|
24
|
+
SAVE_DOWNLOADS_ENDPOINT: str = "api/v1/save_downloads"
|
|
25
|
+
SAVE_TRAJECTORY_ENDPOINT: str = "api/v1/save_trajectory"
|
|
26
|
+
INITIATE_CALLBACK_ENDPOINT: str = "api/v1/initiate_callback"
|
|
27
|
+
GET_CALLBACK_DATA_ENDPOINT: str = "api/v1/get_callback_data"
|
|
28
|
+
FETCH_EMAIL_MESSAGES_ENDPOINT: str = "api/v1/fetch_email_messages"
|
|
29
|
+
FETCH_SLACK_MESSAGES_ENDPOINT: str = "api/v1/fetch_slack_messages"
|
|
30
|
+
|
|
31
|
+
API_KEY: str
|
|
32
|
+
|
|
33
|
+
CHILD_PORT_OFFSET: int = 9000
|
|
34
|
+
DEPLOYMENT: Literal["dev", "prod"]
|
|
35
|
+
LOCAL_CALLBACK_URL: str | None = None
|
|
36
|
+
|
|
37
|
+
PROXY_URL: str | None = None
|
|
38
|
+
PROXY_USERNAME: str | None = None
|
|
39
|
+
PROXY_PASSWORD: str | None = None
|
|
40
|
+
PROXY_COUNTRY: str | None = None
|
|
41
|
+
PROXY_PROVIDER: Literal["oxylabs", "brightdata", "other"] | None = None
|
|
42
|
+
|
|
43
|
+
@model_validator(mode="after")
|
|
44
|
+
def validate_local_callback_url(self):
|
|
45
|
+
if self.DEPLOYMENT == "prod" and self.LOCAL_CALLBACK_URL is not None:
|
|
46
|
+
raise ValueError("LOCAL_CALLBACK_URL is not allowed in prod mode")
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
class Config:
|
|
50
|
+
env_file = env_path if env_path else None
|
|
51
|
+
extra = "allow"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
settings = Settings()
|
optexity/utils/utils.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
import aiofiles
|
|
8
|
+
import pyotp
|
|
9
|
+
from async_lru import alru_cache
|
|
10
|
+
from onepassword import Client as OnePasswordClient
|
|
11
|
+
from pydantic import create_model
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
_onepassword_client = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def get_onepassword_client():
|
|
19
|
+
global _onepassword_client
|
|
20
|
+
if _onepassword_client is None:
|
|
21
|
+
_onepassword_client = await OnePasswordClient.authenticate(
|
|
22
|
+
auth=os.getenv("OP_SERVICE_ACCOUNT_TOKEN"),
|
|
23
|
+
integration_name="Optexity 1Password Integration",
|
|
24
|
+
integration_version="v1.0.0",
|
|
25
|
+
)
|
|
26
|
+
return _onepassword_client
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def build_model(schema: dict, model_name="AutoModel"):
|
|
30
|
+
fields = {}
|
|
31
|
+
for key, value in schema.items():
|
|
32
|
+
if isinstance(value, str): # primitive type
|
|
33
|
+
py_type = eval(value) # e.g., "str" -> str
|
|
34
|
+
fields[key] = (Optional[py_type], None)
|
|
35
|
+
elif isinstance(value, dict): # nested object
|
|
36
|
+
sub_model = build_model(value, model_name=f"{model_name}_{key}")
|
|
37
|
+
fields[key] = (Optional[sub_model], None)
|
|
38
|
+
elif isinstance(value, list): # list of objects or primitives
|
|
39
|
+
if len(value) > 0 and isinstance(value[0], dict):
|
|
40
|
+
sub_model = build_model(value[0], model_name=f"{model_name}_{key}")
|
|
41
|
+
fields[key] = (Optional[List[sub_model]], None)
|
|
42
|
+
else: # list of primitives
|
|
43
|
+
py_type = eval(value[0])
|
|
44
|
+
fields[key] = (Optional[List[py_type]], None)
|
|
45
|
+
return create_model(model_name, **fields)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def save_screenshot(screenshot: str, path: str):
|
|
49
|
+
with open(path, "wb") as f:
|
|
50
|
+
f.write(base64.b64decode(screenshot))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async def save_and_clear_downloaded_files(content: bytes | str, filename: Path):
|
|
54
|
+
if isinstance(content, bytes):
|
|
55
|
+
async with aiofiles.open(filename, "wb") as f:
|
|
56
|
+
await f.write(content)
|
|
57
|
+
elif isinstance(content, str):
|
|
58
|
+
async with aiofiles.open(filename, "w") as f:
|
|
59
|
+
await f.write(content)
|
|
60
|
+
else:
|
|
61
|
+
logger.error(f"Unsupported content type: {type(content)}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def get_totp_code(totp_secret: str, digits: int = 6):
|
|
65
|
+
totp = pyotp.TOTP(totp_secret, digits=digits)
|
|
66
|
+
return totp.now()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@alru_cache(maxsize=1000)
|
|
70
|
+
async def get_onepassword_value(vault_name: str, item_name: str, field_name: str):
|
|
71
|
+
client = await get_onepassword_client()
|
|
72
|
+
str_value = await client.secrets.resolve(
|
|
73
|
+
f"op://{vault_name}/{item_name}/{field_name}"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return str_value
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
optexity/__init__.py,sha256=dqh4tGEzruZnkvRLjPYKyc2-FVlXLx1Dj-JNy5fy7U8,459
|
|
2
|
+
optexity/cli.py,sha256=bpHwMWGGJVS3TG2uUl2nSJkf916D-kCw_mxzAe_-XeI,2238
|
|
3
|
+
optexity/exceptions.py,sha256=j4QxbcnAl5RmEJPJ0MWZ0iM38HvW-r8xmxtDxZ1ceSY,269
|
|
4
|
+
optexity/onepassword_integration.py,sha256=_1sQ8sRGVdDnA7384FXiXYRVntPB-ZQAu8W7ICX7_VQ,1047
|
|
5
|
+
optexity/test.py,sha256=pMSZwwA8tj6jAfFUJ3OUHGnTPriqkv4eDGGHqdAdrsA,2797
|
|
6
|
+
optexity/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
optexity/examples/add_example.py,sha256=jVPd2pQ9lnmdwsVsld52CkRafYcF60SrQyDU3QFKTwY,2474
|
|
8
|
+
optexity/examples/download_pdf_url.py,sha256=mB1Kp0UC4AuHeIiyxMt5tlNK5urNPUosHjmUvV67qdM,829
|
|
9
|
+
optexity/examples/extract_price_stockanalysis.py,sha256=oUMAXW0TKFjJO6KCDIsThaMwNNC_Zx5_ZfkuYTo9xmE,1520
|
|
10
|
+
optexity/examples/file_upload.py,sha256=Ep9wxjZFjlcWVufkhLt_RufZMbC8BJ8amASFO7uKGCk,2030
|
|
11
|
+
optexity/examples/i94.py,sha256=QB-Vo6jB03wOovsNh6_TsdxvdJf3MbnxVeUlEoVtUhA,4534
|
|
12
|
+
optexity/examples/i94_travel_history.py,sha256=PbU-xg3xVoEgRPaZQfC5JPNcHA6ClTu8X7650TK1_dc,4573
|
|
13
|
+
optexity/examples/peachstate_medicaid.py,sha256=0PQN3SI5NGw0m95ODm-bHYgF0xwpA83_9xflnN8P4mM,8290
|
|
14
|
+
optexity/examples/supabase_login.py,sha256=_j5VZi0HkqpWl0xguMoHc3gfkf3FiJWnQPs8D_QARN4,2349
|
|
15
|
+
optexity/inference/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
optexity/inference/child_process.py,sha256=0-HoM9yUtYf7BzfCeKS_uUO4NfrdAESryuHaKYRwEoY,8098
|
|
17
|
+
optexity/inference/run_local.py,sha256=P-ghDcNhHESuG7Q6Qp6xdl6r0g2lAyDkIhKsyaLBcPs,6743
|
|
18
|
+
optexity/inference/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
optexity/inference/agents/error_handler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
optexity/inference/agents/error_handler/error_handler.py,sha256=95T19gFgdvOcD1lVbEDmuB9-D5LB_08xAjSc2ezyaCs,1111
|
|
21
|
+
optexity/inference/agents/error_handler/prompt.py,sha256=911fxUvQzG2OhjstGSB0ioDOeZopmuHCfPVOY4cZSbM,4333
|
|
22
|
+
optexity/inference/agents/index_prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
+
optexity/inference/agents/index_prediction/action_prediction_locator_axtree.py,sha256=KJdBss76h92iYpiwdwBUhsfhtGeVnhsGMokdJvGsjj4,1280
|
|
24
|
+
optexity/inference/agents/index_prediction/prompt.py,sha256=51nMQExOmVEVoMWr2hkYGdR9_yDMXt0m1LxhILILT2E,1005
|
|
25
|
+
optexity/inference/agents/select_value_prediction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
optexity/inference/agents/select_value_prediction/prompt.py,sha256=r59j6P4TN-NtGjpmtTsjLxH_nsoLeukMNDE0_cVqj_4,1351
|
|
27
|
+
optexity/inference/agents/select_value_prediction/select_value_prediction.py,sha256=QlBdZRW_QJ1xS8b8CY25UlPHcS1obuwKxjVoZl9b30k,1167
|
|
28
|
+
optexity/inference/agents/two_fa_extraction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
|
+
optexity/inference/agents/two_fa_extraction/prompt.py,sha256=eAqz_InZeyTnFqPMeYm-xyF7rtFWMBIF7nQW3QJnW08,1328
|
|
30
|
+
optexity/inference/agents/two_fa_extraction/two_fa_extraction.py,sha256=UcBo_Iyx6Kqas-fUZpJgos5R-t2hQ2PZUFjtHmO9Rh0,1444
|
|
31
|
+
optexity/inference/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
optexity/inference/core/logging.py,sha256=Zq2KL6XWlPIgsJjprxv-BLsnP5MAAKS2ciNMNkQrfBU,13870
|
|
33
|
+
optexity/inference/core/run_assertion.py,sha256=8ydAkSA2E0VajwKZlY2z4Xxxyzo49UsFIZ7ej_l0Cy8,2224
|
|
34
|
+
optexity/inference/core/run_automation.py,sha256=aXsEj3M7BN_VlpDZgZdScsQHB7jfukCAKGvyBSjUMjA,16708
|
|
35
|
+
optexity/inference/core/run_extraction.py,sha256=TaUfFCcKxuMEJELDhcYMjpbyxgRrdVMHNIX6pjo7l5U,7576
|
|
36
|
+
optexity/inference/core/run_interaction.py,sha256=Rs6Sa4cqTpR1jNNPh2IRYfj4sKcFgtWbjTaQN-wRICs,9248
|
|
37
|
+
optexity/inference/core/run_python_script.py,sha256=WjnCmckZz7YmoLTGBLZeFWhhS1s_x0-kgyKYTM17JHI,547
|
|
38
|
+
optexity/inference/core/run_two_fa.py,sha256=m1lxPefJHtXqMYBB0oONxd5f7XX8AI5eUkjjjs5y0Z0,4010
|
|
39
|
+
optexity/inference/core/interaction/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
optexity/inference/core/interaction/handle_agentic_task.py,sha256=MSURLDM-2Hw37sipa3lqUBh1NNFrGmx2DPGJsBGYTDg,2617
|
|
41
|
+
optexity/inference/core/interaction/handle_check.py,sha256=_LEA5V6h4x8fozAvPsGrFUZUaO0uU34z2R9VzGIOdio,1489
|
|
42
|
+
optexity/inference/core/interaction/handle_click.py,sha256=IhdYjj-oNGoJInN9XK6ppqW6JQgCNm7t2COymv5T9O8,2249
|
|
43
|
+
optexity/inference/core/interaction/handle_command.py,sha256=a0Eqs5eDJ4bPttqMh4r_IAYJzpXcH9bvUS_9CG8MySA,8350
|
|
44
|
+
optexity/inference/core/interaction/handle_input.py,sha256=UGALiQLUgjgg5Z-vj4lEoEs4_GXCirUBgONUulKs0oU,2256
|
|
45
|
+
optexity/inference/core/interaction/handle_keypress.py,sha256=Ig-U7qoMQ1GIaxeS2TnSTe4N3Jj64WcVc1rwl7Z-0So,466
|
|
46
|
+
optexity/inference/core/interaction/handle_select.py,sha256=1nTm-hyaG4xDnItdulW1--b0zj20FdJq7qks5X-aNKU,3236
|
|
47
|
+
optexity/inference/core/interaction/handle_select_utils.py,sha256=gJnIvBNPFwIkFjYiaVSB-91k95leahrSnlq8fgDcWbQ,4114
|
|
48
|
+
optexity/inference/core/interaction/handle_upload.py,sha256=cIe9lcgA8_jT1KMGcImfqq_PEEVY-Fy5YZjrX2GA8As,1818
|
|
49
|
+
optexity/inference/core/interaction/utils.py,sha256=iWKfn7cF-8duQoMvGfmGV05oOuQEyKPgOdMJe_Hk4KM,2745
|
|
50
|
+
optexity/inference/core/two_factor_auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
+
optexity/inference/infra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
52
|
+
optexity/inference/infra/browser.py,sha256=GpECOdxhpe5AbwU2FnRmR7jevKUiHHEZCq7PgpMI8t0,15955
|
|
53
|
+
optexity/inference/infra/browser_extension.py,sha256=Ur5_8DrHcgRkD9uulDsVaaj01z1WcsvqHxHok4p4RoM,589
|
|
54
|
+
optexity/inference/models/__init__.py,sha256=f66ea3I8ibNrkn4Uf_wYIn-2eoP-ReXds03LgaopOfA,667
|
|
55
|
+
optexity/inference/models/gemini.py,sha256=ToncY6Ft4kOgIm6qREBVsScT8FG-JCrdWsBxYOgU0is,4100
|
|
56
|
+
optexity/inference/models/human.py,sha256=K2X6Ohg7xeTWDYkJY6lOAwS9T3nX7YST-cvd8nL1Ydw,394
|
|
57
|
+
optexity/inference/models/llm_model.py,sha256=nZvcrQs4XDI07ckFUf6o-TzvyqW-I4WIbos7WEo4hz8,7211
|
|
58
|
+
optexity/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
59
|
+
optexity/schema/automation.py,sha256=by9pcgCpG1yDEowBQGeVa30vQ3hO-GCtTiJdcSf4RKY,16121
|
|
60
|
+
optexity/schema/callback.py,sha256=MlN41A6oKG7QX01_w0tsxyAFKWnoCVsu_mjpWzPMYuE,519
|
|
61
|
+
optexity/schema/inference.py,sha256=8mP49IRU-cRxbsC4NnoGZhd5isvdocCuMVspPBOQV9o,2864
|
|
62
|
+
optexity/schema/memory.py,sha256=e3AMDAivCF_KnKbeDugqVLib8UN_6dr3ksUCiWaeIGM,3072
|
|
63
|
+
optexity/schema/task.py,sha256=qv41fXKSVhxVtS5zrS9ihv35ZVZAXlbcTFO2hVrjBlc,6794
|
|
64
|
+
optexity/schema/token_usage.py,sha256=iwZjUqTrNhrEBMeeZNMWqD4qs2toKDczRVoDTOLLNso,2114
|
|
65
|
+
optexity/schema/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
+
optexity/schema/actions/assertion_action.py,sha256=lcD6h7phacrEoB5j-It9qP9Ym3TKb1bkv1aa8tqwG-Q,1991
|
|
67
|
+
optexity/schema/actions/extraction_action.py,sha256=-d6JaumXRZctiXNqndKE1QOWUR7fllglJ4rGuBpiVNw,4771
|
|
68
|
+
optexity/schema/actions/interaction_action.py,sha256=99KuL6waCMnTB3iK6tyeatRjnIV8yhghBSLkY-_rSDo,10728
|
|
69
|
+
optexity/schema/actions/misc_action.py,sha256=VZvaVemTlCoUwSomA42EX74L81-ICDYNWqJAuWNtyyE,312
|
|
70
|
+
optexity/schema/actions/prompts.py,sha256=GZud5T2kQvQKhAXHmAnalVUP8iMcDz8be3jRp-vAInk,1772
|
|
71
|
+
optexity/schema/actions/two_fa_action.py,sha256=OzzTDX3fZObWJiw8hvNgr96PBcvpDh1uONPfHrPFLf8,564
|
|
72
|
+
optexity/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
+
optexity/utils/settings.py,sha256=h6StXzYslRgZf0c8k43-kOxoa77dOgDvSOvfQUi5yI8,1864
|
|
74
|
+
optexity/utils/utils.py,sha256=QgVeKK3jAq-TLgP_RYiCXRAOEbuypFox0RxYEjruoTA,2565
|
|
75
|
+
optexity-0.1.3.dist-info/licenses/LICENSE,sha256=WpSBqSAcwd68PmS3zRsfACJOz-u-UfTzftsEnzp4ZCY,1065
|
|
76
|
+
optexity-0.1.3.dist-info/METADATA,sha256=OD8o3LPPu3HUgVd8dls3I-NDOTsdxWuJjrHdnRRyrwE,10613
|
|
77
|
+
optexity-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
78
|
+
optexity-0.1.3.dist-info/entry_points.txt,sha256=hcn77ooRr6a_N8fo0vij3Fpo6waqc9ijpaScQ7Kj35k,47
|
|
79
|
+
optexity-0.1.3.dist-info/top_level.txt,sha256=OZEtBX8IabC8EnBrNW98z7NzdGQsjFhHleSthhjjEMM,9
|
|
80
|
+
optexity-0.1.3.dist-info/RECORD,,
|
optexity-0.1.2.dist-info/RECORD
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
optexity/__init__.py,sha256=dqh4tGEzruZnkvRLjPYKyc2-FVlXLx1Dj-JNy5fy7U8,459
|
|
2
|
-
optexity/cli.py,sha256=bpHwMWGGJVS3TG2uUl2nSJkf916D-kCw_mxzAe_-XeI,2238
|
|
3
|
-
optexity/exceptions.py,sha256=j4QxbcnAl5RmEJPJ0MWZ0iM38HvW-r8xmxtDxZ1ceSY,269
|
|
4
|
-
optexity/onepassword_integration.py,sha256=_1sQ8sRGVdDnA7384FXiXYRVntPB-ZQAu8W7ICX7_VQ,1047
|
|
5
|
-
optexity/test.py,sha256=pMSZwwA8tj6jAfFUJ3OUHGnTPriqkv4eDGGHqdAdrsA,2797
|
|
6
|
-
optexity-0.1.2.dist-info/licenses/LICENSE,sha256=WpSBqSAcwd68PmS3zRsfACJOz-u-UfTzftsEnzp4ZCY,1065
|
|
7
|
-
optexity-0.1.2.dist-info/METADATA,sha256=hVH-kaFUYJHPOIF5-PVJGA3x8YMUNCjGYpW3J23dXmk,10613
|
|
8
|
-
optexity-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
9
|
-
optexity-0.1.2.dist-info/entry_points.txt,sha256=hcn77ooRr6a_N8fo0vij3Fpo6waqc9ijpaScQ7Kj35k,47
|
|
10
|
-
optexity-0.1.2.dist-info/top_level.txt,sha256=OZEtBX8IabC8EnBrNW98z7NzdGQsjFhHleSthhjjEMM,9
|
|
11
|
-
optexity-0.1.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|