oagi 0.4.2__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of oagi might be problematic. Click here for more details.
- {oagi-0.4.2 → oagi-0.4.3}/.github/workflows/release.yml +10 -3
- {oagi-0.4.2 → oagi-0.4.3}/PKG-INFO +1 -1
- {oagi-0.4.2 → oagi-0.4.3}/pyproject.toml +1 -1
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/pyautogui_action_handler.py +18 -1
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_pyautogui_action_handler.py +70 -0
- {oagi-0.4.2 → oagi-0.4.3}/uv.lock +1 -1
- {oagi-0.4.2 → oagi-0.4.3}/.github/workflows/ci.yml +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/.gitignore +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/.python-version +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/CONTRIBUTING.md +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/LICENSE +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/Makefile +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/README.md +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/async_google_weather.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/execute_task_auto.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/execute_task_manual.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/google_weather.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/hotel_booking.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/screenshot_with_config.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/examples/single_step.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/__init__.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_client.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_pyautogui_action_handler.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_screenshot_maker.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_short_task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_single_step.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/async_task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/exceptions.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/logging.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/pil_image.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/screenshot_maker.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/short_task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/single_step.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/sync_client.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/__init__.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/action_handler.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/async_action_handler.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/async_image_provider.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/image.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/image_provider.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/models/__init__.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/models/action.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/models/image_config.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/src/oagi/types/models/step.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/__init__.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/conftest.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_async_client.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_async_handlers.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_async_task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_logging.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_pil_image.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_screenshot_maker.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_short_task.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_single_step.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_sync_client.py +0 -0
- {oagi-0.4.2 → oagi-0.4.3}/tests/test_task.py +0 -0
|
@@ -32,10 +32,17 @@ jobs:
|
|
|
32
32
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
33
33
|
# Another option: Use Trusted Publishing (recommended, no token needed)
|
|
34
34
|
# Configure at: https://pypi.org/manage/project/oagi/settings/publishing/
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
- name: Get commit message
|
|
37
|
+
id: commit_message
|
|
38
|
+
run: |
|
|
39
|
+
# Get the commit message for the tagged commit
|
|
40
|
+
echo "message<<EOF" >> $GITHUB_OUTPUT
|
|
41
|
+
git log -1 --pretty=%B >> $GITHUB_OUTPUT
|
|
42
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
36
43
|
|
|
37
44
|
- name: Create GitHub Release
|
|
38
45
|
uses: softprops/action-gh-release@v1
|
|
39
46
|
with:
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
body: ${{ steps.commit_message.outputs.message }}
|
|
48
|
+
files: dist/*
|
|
@@ -101,9 +101,26 @@ class PyautoguiActionHandler:
|
|
|
101
101
|
self.caps_manager = CapsLockManager(mode=self.config.capslock_mode)
|
|
102
102
|
|
|
103
103
|
def _denormalize_coords(self, x: float, y: float) -> tuple[int, int]:
|
|
104
|
-
"""Convert coordinates from 0-1000 range to actual screen coordinates.
|
|
104
|
+
"""Convert coordinates from 0-1000 range to actual screen coordinates.
|
|
105
|
+
|
|
106
|
+
Also handles corner coordinates to prevent PyAutoGUI fail-safe trigger.
|
|
107
|
+
Corner coordinates (0,0), (0,max), (max,0), (max,max) are offset by 1 pixel.
|
|
108
|
+
"""
|
|
105
109
|
screen_x = int(x * self.screen_width / 1000)
|
|
106
110
|
screen_y = int(y * self.screen_height / 1000)
|
|
111
|
+
|
|
112
|
+
# Prevent fail-safe by adjusting corner coordinates
|
|
113
|
+
# Check if coordinates are at screen corners (with small tolerance)
|
|
114
|
+
if screen_x < 1:
|
|
115
|
+
screen_x = 1
|
|
116
|
+
elif screen_x > self.screen_width - 1:
|
|
117
|
+
screen_x = self.screen_width - 1
|
|
118
|
+
|
|
119
|
+
if screen_y < 1:
|
|
120
|
+
screen_y = 1
|
|
121
|
+
elif screen_y > self.screen_height - 1:
|
|
122
|
+
screen_y = self.screen_height - 1
|
|
123
|
+
|
|
107
124
|
return screen_x, screen_y
|
|
108
125
|
|
|
109
126
|
def _parse_coords(self, args_str: str) -> tuple[int, int]:
|
|
@@ -196,6 +196,76 @@ class TestCapsLockManager:
|
|
|
196
196
|
assert system_manager.should_use_system_capslock() is True
|
|
197
197
|
|
|
198
198
|
|
|
199
|
+
class TestCornerCoordinatesHandling:
|
|
200
|
+
"""Test that corner coordinates are adjusted to prevent PyAutoGUI fail-safe."""
|
|
201
|
+
|
|
202
|
+
@pytest.mark.parametrize(
|
|
203
|
+
"input_coords,expected_coords",
|
|
204
|
+
[
|
|
205
|
+
# Top-left corner
|
|
206
|
+
("0, 0", (1, 1)),
|
|
207
|
+
("1, 1", (1, 1)),
|
|
208
|
+
# Top-right corner (assuming 1920x1080 screen)
|
|
209
|
+
("1000, 0", (1919, 1)),
|
|
210
|
+
("999, 1", (1918, 1)),
|
|
211
|
+
# Bottom-left corner
|
|
212
|
+
("0, 1000", (1, 1079)),
|
|
213
|
+
("1, 999", (1, 1078)),
|
|
214
|
+
# Bottom-right corner
|
|
215
|
+
("1000, 1000", (1919, 1079)),
|
|
216
|
+
("999, 999", (1918, 1078)),
|
|
217
|
+
# Middle coordinates should not be affected
|
|
218
|
+
("500, 500", (960, 540)),
|
|
219
|
+
("250, 750", (480, 810)),
|
|
220
|
+
],
|
|
221
|
+
)
|
|
222
|
+
def test_corner_coordinate_adjustment(
|
|
223
|
+
self, mock_pyautogui, input_coords, expected_coords
|
|
224
|
+
):
|
|
225
|
+
handler = PyautoguiActionHandler()
|
|
226
|
+
action = Action(type=ActionType.CLICK, argument=input_coords, count=1)
|
|
227
|
+
handler([action])
|
|
228
|
+
mock_pyautogui.click.assert_called_once_with(*expected_coords)
|
|
229
|
+
|
|
230
|
+
def test_drag_with_corner_coordinates(self, mock_pyautogui, config):
|
|
231
|
+
"""Test drag operations with corner coordinates."""
|
|
232
|
+
handler = PyautoguiActionHandler()
|
|
233
|
+
# Drag from top-left corner to bottom-right corner
|
|
234
|
+
action = Action(type=ActionType.DRAG, argument="0, 0, 1000, 1000", count=1)
|
|
235
|
+
handler([action])
|
|
236
|
+
|
|
237
|
+
# Should adjust corner coordinates to prevent fail-safe
|
|
238
|
+
mock_pyautogui.moveTo.assert_called_once_with(1, 1)
|
|
239
|
+
mock_pyautogui.dragTo.assert_called_once_with(
|
|
240
|
+
1919, 1079, duration=config.drag_duration, button="left"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
def test_scroll_with_corner_coordinates(self, mock_pyautogui, config):
|
|
244
|
+
"""Test scroll operations at corner coordinates."""
|
|
245
|
+
handler = PyautoguiActionHandler()
|
|
246
|
+
action = Action(type=ActionType.SCROLL, argument="0, 0, up", count=1)
|
|
247
|
+
handler([action])
|
|
248
|
+
|
|
249
|
+
# Should adjust corner coordinates
|
|
250
|
+
mock_pyautogui.moveTo.assert_called_once_with(1, 1)
|
|
251
|
+
mock_pyautogui.scroll.assert_called_once_with(config.scroll_amount)
|
|
252
|
+
|
|
253
|
+
def test_multiple_clicks_at_corners(self, mock_pyautogui):
|
|
254
|
+
"""Test multiple clicks at corner positions."""
|
|
255
|
+
handler = PyautoguiActionHandler()
|
|
256
|
+
actions = [
|
|
257
|
+
Action(type=ActionType.LEFT_DOUBLE, argument="0, 0", count=1),
|
|
258
|
+
Action(type=ActionType.LEFT_TRIPLE, argument="1000, 0", count=1),
|
|
259
|
+
Action(type=ActionType.RIGHT_SINGLE, argument="0, 1000", count=1),
|
|
260
|
+
]
|
|
261
|
+
handler(actions)
|
|
262
|
+
|
|
263
|
+
# All corner coordinates should be adjusted
|
|
264
|
+
mock_pyautogui.doubleClick.assert_called_once_with(1, 1)
|
|
265
|
+
mock_pyautogui.tripleClick.assert_called_once_with(1919, 1)
|
|
266
|
+
mock_pyautogui.rightClick.assert_called_once_with(1, 1079)
|
|
267
|
+
|
|
268
|
+
|
|
199
269
|
class TestCapsLockIntegration:
|
|
200
270
|
def test_caps_lock_key_normalization(self, mock_pyautogui):
|
|
201
271
|
handler = PyautoguiActionHandler()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|