oagi-core 0.14.0__py3-none-any.whl → 0.14.2__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.
@@ -12,8 +12,10 @@ from pydantic import BaseModel, Field
12
12
 
13
13
  from oagi.handler.screen_manager import Screen
14
14
 
15
+ from ..constants import DEFAULT_STEP_DELAY
15
16
  from ..types import Action, ActionType, parse_coords, parse_drag_coords, parse_scroll
16
17
  from .capslock_manager import CapsLockManager
18
+ from .utils import CoordinateScaler, normalize_key, parse_hotkey
17
19
  from .wayland_support import Ydotool, get_screen_size
18
20
 
19
21
 
@@ -38,6 +40,12 @@ class YdotoolConfig(BaseModel):
38
40
  default="",
39
41
  description="Custom socket address for ydotool (e.g., '/tmp/ydotool.sock')",
40
42
  )
43
+ post_batch_delay: float = Field(
44
+ default=DEFAULT_STEP_DELAY,
45
+ ge=0,
46
+ description="Delay after executing all actions in a batch (seconds). "
47
+ "Allows UI to settle before next screenshot.",
48
+ )
41
49
 
42
50
 
43
51
  class YdotoolActionHandler(Ydotool):
@@ -66,6 +74,13 @@ class YdotoolActionHandler(Ydotool):
66
74
  self.caps_manager = CapsLockManager(mode=self.config.capslock_mode)
67
75
  # The origin position of coordinates (the top-left corner of the screen)
68
76
  self.origin_x, self.origin_y = 0, 0
77
+ # Initialize coordinate scaler
78
+ self._coord_scaler = CoordinateScaler(
79
+ source_width=1000,
80
+ source_height=1000,
81
+ target_width=self.screen_width,
82
+ target_height=self.screen_height,
83
+ )
69
84
 
70
85
  def reset(self):
71
86
  """Reset handler state.
@@ -83,6 +98,12 @@ class YdotoolActionHandler(Ydotool):
83
98
  """
84
99
  self.screen_width, self.screen_height = screen.width, screen.height
85
100
  self.origin_x, self.origin_y = screen.x, screen.y
101
+ self._coord_scaler = CoordinateScaler(
102
+ source_width=1000,
103
+ source_height=1000,
104
+ target_width=self.screen_width,
105
+ target_height=self.screen_height,
106
+ )
86
107
 
87
108
  def _execute_action(self, action: Action) -> bool:
88
109
  """
@@ -161,45 +182,14 @@ class YdotoolActionHandler(Ydotool):
161
182
  return finished
162
183
 
163
184
  def _denormalize_coords(self, x: float, y: float) -> tuple[int, int]:
164
- """Convert coordinates from 0-1000 range to actual screen coordinates.
165
-
166
- Also handles corner coordinates to prevent PyAutoGUI fail-safe trigger.
167
- Corner coordinates (0,0), (0,max), (max,0), (max,max) are offset by 1 pixel.
168
- """
169
- screen_x = int(x * self.screen_width / 1000)
170
- screen_y = int(y * self.screen_height / 1000)
171
-
172
- # Prevent fail-safe by adjusting corner coordinates
173
- # Check if coordinates are at screen corners (with small tolerance)
174
- if screen_x < 1:
175
- screen_x = 1
176
- elif screen_x > self.screen_width - 1:
177
- screen_x = self.screen_width - 1
178
-
179
- if screen_y < 1:
180
- screen_y = 1
181
- elif screen_y > self.screen_height - 1:
182
- screen_y = self.screen_height - 1
183
-
184
- # Add origin offset to convert relative to top-left corner
185
- screen_x += self.origin_x
186
- screen_y += self.origin_y
187
-
188
- return screen_x, screen_y
185
+ """Convert coordinates from 0-1000 range to actual screen coordinates."""
186
+ screen_x, screen_y = self._coord_scaler.scale(x, y, prevent_failsafe=True)
187
+ # Add origin offset for multi-screen support
188
+ return screen_x + self.origin_x, screen_y + self.origin_y
189
189
 
190
190
  def _normalize_key(self, key: str) -> str:
191
191
  """Normalize key names for consistency."""
192
- key = key.strip().lower()
193
- # Normalize caps lock variations
194
- hotkey_variations_mapping = {
195
- "capslock": ["caps_lock", "caps", "capslock"],
196
- "pgup": ["page_up", "pageup"],
197
- "pgdn": ["page_down", "pagedown"],
198
- }
199
- for normalized, variations in hotkey_variations_mapping.items():
200
- if key in variations:
201
- return normalized
202
- return key
192
+ return normalize_key(key)
203
193
 
204
194
  def _parse_coords(self, args_str: str) -> tuple[int, int]:
205
195
  """Extract x, y coordinates from argument string."""
@@ -227,11 +217,7 @@ class YdotoolActionHandler(Ydotool):
227
217
 
228
218
  def _parse_hotkey(self, args_str: str) -> list[str]:
229
219
  """Parse hotkey string into list of keys."""
230
- # Remove parentheses if present
231
- args_str = args_str.strip("()")
232
- # Split by '+' to get individual keys
233
- keys = [self._normalize_key(key) for key in args_str.split("+")]
234
- return keys
220
+ return parse_hotkey(args_str.strip("()"), validate=False)
235
221
 
236
222
  def __call__(self, actions: list[Action]) -> None:
237
223
  """Execute the provided list of actions."""
@@ -241,3 +227,7 @@ class YdotoolActionHandler(Ydotool):
241
227
  except Exception as e:
242
228
  print(f"Error executing action {action.type}: {e}")
243
229
  raise
230
+
231
+ # Wait after batch for UI to settle before next screenshot
232
+ if self.config.post_batch_delay > 0:
233
+ time.sleep(self.config.post_batch_delay)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: oagi-core
3
- Version: 0.14.0
3
+ Version: 0.14.2
4
4
  Summary: Official API of OpenAGI Foundation
5
5
  Project-URL: Homepage, https://github.com/agiopen-org/oagi
6
6
  Author-email: OpenAGI Foundation <contact@agiopen.org>
@@ -154,12 +154,15 @@ from oagi import AsyncPyautoguiActionHandler, PyautoguiConfig
154
154
 
155
155
  # Customize action behavior
156
156
  config = PyautoguiConfig(
157
- drag_duration=1.0, # Slower drags for precision (default: 0.5)
158
- scroll_amount=50, # Larger scroll steps (default: 30)
159
- wait_duration=2.0, # Longer waits (default: 1.0)
160
- action_pause=0.2, # More pause between actions (default: 0.1)
161
- hotkey_interval=0.1, # Interval between keys in hotkey combinations (default: 0.1)
162
- capslock_mode="session" # Caps lock mode: 'session' or 'system' (default: 'session')
157
+ drag_duration=1.0, # Slower drags for precision (default: 0.5)
158
+ scroll_amount=50, # Larger scroll steps (default: 2 on macOS, 100 on others)
159
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
160
+ action_pause=0.2, # Pause between PyAutoGUI calls (default: 0.1)
161
+ hotkey_interval=0.1, # Interval between keys in hotkey combos (default: 0.1)
162
+ capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
163
+ macos_ctrl_to_cmd=True, # Replace ctrl with cmd on macOS (default: True)
164
+ click_pre_delay=0.1, # Delay after move before click (default: 0.1)
165
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
163
166
  )
164
167
 
165
168
  action_handler = AsyncPyautoguiActionHandler(config=config)
@@ -279,10 +282,11 @@ from oagi import AsyncYdotoolActionHandler, YdotoolConfig
279
282
  # Customize action behavior
280
283
  config = YdotoolConfig(
281
284
  scroll_amount=50, # Larger scroll steps (default: 20)
282
- wait_duration=2.0, # Longer waits (default: 1.0)
283
- action_pause=1.0, # More pause between actions (default: 0.5)
285
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
286
+ action_pause=1.0, # Pause between Ydotool calls (default: 0.5)
284
287
  capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
285
- socket_address="/tmp/ydotool.sock" # Customized Socket address for ydotool (ydotool uses 'YDOTOOL_SOCKET' environment variable by default)
288
+ socket_address="/tmp/ydotool.sock", # Custom socket address (default: YDOTOOL_SOCKET env var)
289
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
286
290
  )
287
291
 
288
292
  action_handler = AsyncYdotoolActionHandler(config=config)
@@ -1,4 +1,4 @@
1
- oagi/__init__.py,sha256=TVBbIMEXQh5Z8JumqrivMPBLYt3E5HmGPi973NDx2Qs,5797
1
+ oagi/__init__.py,sha256=Ft-HT7yXmX9HkHewjn_kQIFJcDj-_KSLgOLNgZeBlyU,6286
2
2
  oagi/constants.py,sha256=qcNisliLRZUr6krXpS49AAPfFYvkZuWQcAJ8ZdEnhic,1228
3
3
  oagi/exceptions.py,sha256=Rco37GQTPYUfc2vRO3hozxPF_s8mKFDpFvBg2UKWo3Y,3066
4
4
  oagi/logging.py,sha256=YT3KCMFj5fzO98R9xlDDgfSotUuz1xRD6OZeYM2rKoo,1760
@@ -10,7 +10,7 @@ oagi/actor/base.py,sha256=-ecocyZ9-NQ4C4jjsHLUcs3ixZ99rFbzqwFsiVKZVR0,8001
10
10
  oagi/actor/short.py,sha256=wKLCxvf7Ys6rYxXpHe4zbZdbf_1q1qcmm5WyWubwj3E,2630
11
11
  oagi/actor/sync.py,sha256=QTY1WNTI75jwkWBghdVViHIp5rYkbm3kumlLedU8YeQ,3588
12
12
  oagi/agent/__init__.py,sha256=KTVLUMhbjgpTJoOWMUZkkiqwhgumvbOZV2tJ9XCLfao,901
13
- oagi/agent/default.py,sha256=Ax05kBa8Fb14Ev8wd9LS6xkF65grf6qdxxTlgpkkDuk,4715
13
+ oagi/agent/default.py,sha256=mP4Gdld5I0sP0ANyn1CLkFvgk9qPkzYbwJeZUGhlsew,4712
14
14
  oagi/agent/factories.py,sha256=syi_EOlU4SUjo-0CKaML8eIPu3ToUEKua2VHp9lvNF0,5839
15
15
  oagi/agent/protocol.py,sha256=IQJGiMN4yZIacrh5e9JQsoM9TyHb8wJRQR4LAk8dSA0,1615
16
16
  oagi/agent/registry.py,sha256=7bMA2-pH3xQ9ZavrHB_mnc2fOGSMeICPbOGtHoM7It0,4851
@@ -24,7 +24,7 @@ oagi/agent/tasker/__init__.py,sha256=1iTEFe7lzcqh96TL9R0QADPpLJLrUP0shtZ4DlZSv_8
24
24
  oagi/agent/tasker/memory.py,sha256=NR13l5yxRA8GUE-oupAP4W1n80ZNG0SxpUfxsNltkUY,5033
25
25
  oagi/agent/tasker/models.py,sha256=sMQgwIMKhT1tvVF2yoc1hh8GwEiJ6i6qPMy9WoiA8JM,2137
26
26
  oagi/agent/tasker/planner.py,sha256=q6IvH6sfU2kYX1NcC9VHjGaQ0X9jF18yjuAYXisNCg0,15489
27
- oagi/agent/tasker/taskee_agent.py,sha256=OugYJbTbFKxgNjbIyQBBH4Zm5u5PuWN1F6R81_eIro8,18090
27
+ oagi/agent/tasker/taskee_agent.py,sha256=IfRg_YixHkxHuiGCqok5cPDLD7PXUqlsoRAfWnWswMI,18091
28
28
  oagi/agent/tasker/tasker_agent.py,sha256=yb0BdQzJyAPpK3njHPWgQruV8zpUGBXn1WjOGEMIO-g,11291
29
29
  oagi/cli/__init__.py,sha256=aDnJViTseShpo5fdGPTj-ELysZhmdvB6Z8mEj2D-_N4,359
30
30
  oagi/cli/agent.py,sha256=CWvwwbo4eiq-USYmDHnKafEX8Nk6zsGsUmNzB4QftkQ,13186
@@ -37,21 +37,24 @@ oagi/client/__init__.py,sha256=F9DShPUdb6vZYmN1fpM1VYzp4MWqUao_e_R1KYmM4Q4,410
37
37
  oagi/client/async_.py,sha256=BANE0KU14WBuXp6suBhr8JSlpWhN5SR2aJJ7wAJBDLQ,9574
38
38
  oagi/client/base.py,sha256=CWAvE0AcpL8HD_i00n7Fq53AIAQGhBhS_n6LifUCqxE,14736
39
39
  oagi/client/sync.py,sha256=4xNqqNihXmgLU385h22mMJ9wmmlw-jeOdWI4fmpEpTk,9369
40
+ oagi/converters/__init__.py,sha256=4ADgInzAQNCvghXT4cKYt8zUnj-V-szjzRnrxJRE5Tw,1875
41
+ oagi/converters/base.py,sha256=0wHVMf9xAqVidBD_VtsqfLDlBPOqUADt6or4JGAha1A,9096
42
+ oagi/converters/oagi.py,sha256=tKvT5Pqq1gMqkVPdqU7p6su8r6IeU5-B4A7hvbHFmMA,7437
40
43
  oagi/handler/__init__.py,sha256=ZMQIeN_uJKUK_dn0w7ggsPfdRzzwts7G-Sppsrt22Lg,2528
41
44
  oagi/handler/_macos.py,sha256=Gs8GrhA_WAyv9Yw0D41duliP32Xk6vouyMeWjWJJT90,5187
42
45
  oagi/handler/_windows.py,sha256=MSgPDYEOetSjbn9eJDSrdzBVlUGgGsTlegaTDc4C4Ss,2828
43
46
  oagi/handler/_ydotool.py,sha256=WjvE6RGRm8j3SEWpgfMw31aow3z3qkiMupuUHYt-QAM,2948
44
- oagi/handler/async_pyautogui_action_handler.py,sha256=ZYySg5dSu4MDX0ngwVUJaX3uZA2CuecPN2UqFnCbnec,2174
47
+ oagi/handler/async_pyautogui_action_handler.py,sha256=vZLf6LyRUzPAr8hGmKQDDyXMmc3ZAhlCCN4dIfi3vnY,2245
45
48
  oagi/handler/async_screenshot_maker.py,sha256=_myV4Rq6X_evCOuatalFSW5nsUDXi_0ej0GQ7V4n3JE,1856
46
49
  oagi/handler/async_ydotool_action_handler.py,sha256=HB4QQk3OaG08g37eLb3EwsnkWKWPrpDei0ZsnBxrGZY,2159
47
50
  oagi/handler/capslock_manager.py,sha256=40LzWt1_1wbncF5koUTdbd9V3eo5Ex_mEWwjtEmHAf4,1878
48
51
  oagi/handler/pil_image.py,sha256=s8UGZ6ALbmOxRO2GL1EUFN7_6ZEFseSE9OHABCe7wek,5380
49
- oagi/handler/pyautogui_action_handler.py,sha256=HvupClYrmYuIx_xvXj5SyacDX781bpZkMGEOeXoSQTU,11301
52
+ oagi/handler/pyautogui_action_handler.py,sha256=vA9c2YGV1dNNx3F4a_MGnpS7O4Ww0A0sWxfvgNTMjnc,11162
50
53
  oagi/handler/screen_manager.py,sha256=FV0-6ZyTVv9yZlAg4Krga0xW9O_LDsk1iaCJjWgET-g,6565
51
54
  oagi/handler/screenshot_maker.py,sha256=740k7NjDRKW6KwVqy_nVoczgVuw9_yTKM0gLFKB1iNs,1600
52
- oagi/handler/utils.py,sha256=jj10z-v4_LUuVb8aClyXkUfZVEaqsWgi3be4t3Gw7oI,697
55
+ oagi/handler/utils.py,sha256=WnYvPkpiNYDnv4EDLfOTdO5gEGuJVpB42G0HQkp6aEg,18173
53
56
  oagi/handler/wayland_support.py,sha256=qUIAQMqc3wp1VIypVmZjFDYT8t0yH0QvikTTV8pD-XA,7905
54
- oagi/handler/ydotool_action_handler.py,sha256=y-mWXM88j3baPPywXqwASSx7GAs7LbqTgpCA1gN4nF0,9262
57
+ oagi/handler/ydotool_action_handler.py,sha256=gH3ujZgwc6722ZqKEMqibzH67PCGbw8paMqNP-wM5Sc,8996
55
58
  oagi/server/__init__.py,sha256=uZx8u3vJUb87kkNzwmmVrgAgbqRu0WxyMIQCLSx56kk,452
56
59
  oagi/server/agent_wrappers.py,sha256=j8va0A7u80bzOM82nndAplK1uaO_T3kufHWScK6kfWM,3263
57
60
  oagi/server/config.py,sha256=AJ1PLKuxrc6pRuur1hm5DwG2g2otxPwOCfKgzIACkSk,1691
@@ -76,8 +79,8 @@ oagi/types/models/step.py,sha256=RSI4H_2rrUBq_xyCoWKaq7JHdJWNobtQppaKC1l0aWU,471
76
79
  oagi/utils/__init__.py,sha256=vHXyX66hEsf33OJJkmZSUjaTYU0UngfbtjcZgxfOj3A,441
77
80
  oagi/utils/output_parser.py,sha256=U7vzmoD8pyzDg23z3vy-L9a_jKPsAlr3x8lIdPszrY8,5322
78
81
  oagi/utils/prompt_builder.py,sha256=_Q1HY82YUrq3jSCTZ3Rszu3qmI3Wn_fmq8hf14NuwQM,2180
79
- oagi_core-0.14.0.dist-info/METADATA,sha256=Y7oBSQFVieDeBMwwVMhsrhMMtSPXjM7PIVm72SfTCtM,16508
80
- oagi_core-0.14.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
81
- oagi_core-0.14.0.dist-info/entry_points.txt,sha256=zzgsOSWX6aN3KUB0Z1it8DMxFFBJBqmZVqMVAJRjYuw,44
82
- oagi_core-0.14.0.dist-info/licenses/LICENSE,sha256=sy5DLA2M29jFT4UfWsuBF9BAr3FnRkYtnAu6oDZiIf8,1075
83
- oagi_core-0.14.0.dist-info/RECORD,,
82
+ oagi_core-0.14.2.dist-info/METADATA,sha256=rb_8vO8vmAfY2wgFWHaO2OqukhFZYYO2KVPBq5SPuGM,16854
83
+ oagi_core-0.14.2.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
84
+ oagi_core-0.14.2.dist-info/entry_points.txt,sha256=zzgsOSWX6aN3KUB0Z1it8DMxFFBJBqmZVqMVAJRjYuw,44
85
+ oagi_core-0.14.2.dist-info/licenses/LICENSE,sha256=sy5DLA2M29jFT4UfWsuBF9BAr3FnRkYtnAu6oDZiIf8,1075
86
+ oagi_core-0.14.2.dist-info/RECORD,,