oagi-core 0.12.1__tar.gz → 0.13.0__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.
- {oagi_core-0.12.1 → oagi_core-0.13.0}/PKG-INFO +42 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/README.md +40 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/metapackage/pyproject.toml +2 -2
- {oagi_core-0.12.1 → oagi_core-0.13.0}/metapackage/uv.lock +5 -5
- {oagi_core-0.12.1 → oagi_core-0.13.0}/pyproject.toml +2 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/__init__.py +27 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/agent.py +17 -7
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/async_.py +6 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/base.py +2 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/sync.py +8 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/__init__.py +8 -0
- oagi_core-0.13.0/src/oagi/handler/_ydotool.py +158 -0
- oagi_core-0.13.0/src/oagi/handler/async_ydotool_action_handler.py +52 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/pil_image.py +6 -0
- oagi_core-0.13.0/src/oagi/handler/wayland_support.py +219 -0
- oagi_core-0.13.0/src/oagi/handler/ydotool_action_handler.py +226 -0
- oagi_core-0.13.0/src/oagi/platform_info.py +51 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/uv.lock +31 -1
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/workflows/ci.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/workflows/release.yml +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.gitignore +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/.python-version +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/CONTRIBUTING.md +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/LICENSE +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/Makefile +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/async_google_weather.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/execute_task_auto.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/execute_task_manual.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/google_weather.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/openai_agent_loop_example.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/screenshot_with_config.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/tasker_agent_example.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/async_.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/async_short.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/base.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/short.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/sync.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/default.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/factories.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/agent_observer.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/events.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/exporters.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/protocol.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/report_template.html +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/protocol.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/registry.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/memory.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/models.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/planner.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/taskee_agent.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/tasker_agent.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/display.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/main.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/server.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/tracking.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/utils.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/constants.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/exceptions.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/_macos.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/_windows.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/async_pyautogui_action_handler.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/async_screenshot_maker.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/capslock_manager.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/pyautogui_action_handler.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/screenshot_maker.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/utils.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/logging.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/agent_wrappers.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/config.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/main.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/models.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/session_store.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/socketio_server.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/task/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/action_handler.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/async_action_handler.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/async_image_provider.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/image.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/image_provider.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/action.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/client.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/image_config.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/step.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/step_observer.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/url.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/output_parser.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/prompt_builder.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/conftest.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_action_parsing.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_actor.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent/test_agent_wrappers.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent/test_default_agent.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent_registry.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_actor.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_client.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_handlers.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_cli.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_logging.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_mac_double_click.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_observer.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_pil_image.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_planner.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_planner_memory.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_pyautogui_action_handler.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_screenshot_maker.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_config.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_session_store.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_socketio_integration.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_sync_client.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_taskee_agent.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_tasker_agent.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/utils/__init__.py +0 -0
- {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/utils/test_output_parser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: oagi-core
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
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>
|
|
@@ -35,6 +35,7 @@ Requires-Dist: pillow>=9.0.0; extra == 'desktop'
|
|
|
35
35
|
Requires-Dist: pyautogui>=0.9.54; extra == 'desktop'
|
|
36
36
|
Requires-Dist: pyobjc-framework-applicationservices>=8.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
37
37
|
Requires-Dist: pyobjc-framework-quartz>=8.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
38
|
+
Requires-Dist: screeninfo>=0.8.1; extra == 'desktop'
|
|
38
39
|
Provides-Extra: server
|
|
39
40
|
Requires-Dist: fastapi[standard]>=0.100.0; extra == 'server'
|
|
40
41
|
Requires-Dist: pydantic-settings>=2.0.0; extra == 'server'
|
|
@@ -82,6 +83,7 @@ With Lux, possibilities are endless. Here are a few examples:
|
|
|
82
83
|
- [Command Line Interface](#command-line-interface)
|
|
83
84
|
- [Image Processing](#image-processing)
|
|
84
85
|
- [Manual Control with Actor](#manual-control-with-actor)
|
|
86
|
+
- [Run On System With Wayland](#run-on-system-with-wayland)
|
|
85
87
|
- [Examples](#examples)
|
|
86
88
|
- [Socket.IO Server (Optional)](#socketio-server-optional)
|
|
87
89
|
- [Installation](#installation-1)
|
|
@@ -239,6 +241,45 @@ async def main():
|
|
|
239
241
|
asyncio.run(main())
|
|
240
242
|
```
|
|
241
243
|
|
|
244
|
+
### Run On System With Wayland
|
|
245
|
+
The SDK includes support for desktop automation on systems with Wayland display, such as Ubuntu/Debain. It leverages `ydotool` and `flameshot` for mouse/keyboard actions and screenshot capture respectively. Please install these two tools on your system in advance and ensure `ydotoold` server is running in the background when running the script.
|
|
246
|
+
|
|
247
|
+
Refer to [ydotool](https://github.com/ReimuNotMoe/ydotool) and [flameshot](https://flameshot.org/#download) for installation instructions. Disable mouse acceleration for more precise mouse control. (In GNOME, run `gsettings set org.gnome.desktop.peripherals.mouse accel-profile 'flat'`)
|
|
248
|
+
|
|
249
|
+
Run tasks automatically with screenshot capture and action execution:
|
|
250
|
+
```python
|
|
251
|
+
import asyncio
|
|
252
|
+
from oagi import AsyncDefaultAgent, AsyncYdotoolActionHandler, AsyncScreenshotMaker
|
|
253
|
+
|
|
254
|
+
async def main():
|
|
255
|
+
agent = AsyncDefaultAgent(max_steps=10)
|
|
256
|
+
completed = await agent.execute(
|
|
257
|
+
"Search weather on Google",
|
|
258
|
+
action_handler=AsyncYdotoolActionHandler(), # Executes mouse/keyboard actions, based on 'ydotool'
|
|
259
|
+
image_provider=AsyncScreenshotMaker(), # Captures screenshots, based on 'flameshot'
|
|
260
|
+
)
|
|
261
|
+
return completed
|
|
262
|
+
|
|
263
|
+
asyncio.run(main())
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Configure Ydotool behavior with custom settings:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from oagi import AsyncYdotoolActionHandler, YdotoolConfig
|
|
270
|
+
|
|
271
|
+
# Customize action behavior
|
|
272
|
+
config = YdotoolConfig(
|
|
273
|
+
scroll_amount=50, # Larger scroll steps (default: 20)
|
|
274
|
+
wait_duration=2.0, # Longer waits (default: 1.0)
|
|
275
|
+
action_pause=1.0, # More pause between actions (default: 0.5)
|
|
276
|
+
capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
|
|
277
|
+
socket_address="/tmp/ydotool.sock" # Customized Socket address for ydotool (ydotool uses 'YDOTOOL_SOCKET' environment variable by default)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
action_handler = AsyncYdotoolActionHandler(config=config)
|
|
281
|
+
```
|
|
282
|
+
|
|
242
283
|
## Examples
|
|
243
284
|
|
|
244
285
|
See the [`examples/`](examples/) directory for more usage patterns:
|
|
@@ -38,6 +38,7 @@ With Lux, possibilities are endless. Here are a few examples:
|
|
|
38
38
|
- [Command Line Interface](#command-line-interface)
|
|
39
39
|
- [Image Processing](#image-processing)
|
|
40
40
|
- [Manual Control with Actor](#manual-control-with-actor)
|
|
41
|
+
- [Run On System With Wayland](#run-on-system-with-wayland)
|
|
41
42
|
- [Examples](#examples)
|
|
42
43
|
- [Socket.IO Server (Optional)](#socketio-server-optional)
|
|
43
44
|
- [Installation](#installation-1)
|
|
@@ -195,6 +196,45 @@ async def main():
|
|
|
195
196
|
asyncio.run(main())
|
|
196
197
|
```
|
|
197
198
|
|
|
199
|
+
### Run On System With Wayland
|
|
200
|
+
The SDK includes support for desktop automation on systems with Wayland display, such as Ubuntu/Debain. It leverages `ydotool` and `flameshot` for mouse/keyboard actions and screenshot capture respectively. Please install these two tools on your system in advance and ensure `ydotoold` server is running in the background when running the script.
|
|
201
|
+
|
|
202
|
+
Refer to [ydotool](https://github.com/ReimuNotMoe/ydotool) and [flameshot](https://flameshot.org/#download) for installation instructions. Disable mouse acceleration for more precise mouse control. (In GNOME, run `gsettings set org.gnome.desktop.peripherals.mouse accel-profile 'flat'`)
|
|
203
|
+
|
|
204
|
+
Run tasks automatically with screenshot capture and action execution:
|
|
205
|
+
```python
|
|
206
|
+
import asyncio
|
|
207
|
+
from oagi import AsyncDefaultAgent, AsyncYdotoolActionHandler, AsyncScreenshotMaker
|
|
208
|
+
|
|
209
|
+
async def main():
|
|
210
|
+
agent = AsyncDefaultAgent(max_steps=10)
|
|
211
|
+
completed = await agent.execute(
|
|
212
|
+
"Search weather on Google",
|
|
213
|
+
action_handler=AsyncYdotoolActionHandler(), # Executes mouse/keyboard actions, based on 'ydotool'
|
|
214
|
+
image_provider=AsyncScreenshotMaker(), # Captures screenshots, based on 'flameshot'
|
|
215
|
+
)
|
|
216
|
+
return completed
|
|
217
|
+
|
|
218
|
+
asyncio.run(main())
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Configure Ydotool behavior with custom settings:
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from oagi import AsyncYdotoolActionHandler, YdotoolConfig
|
|
225
|
+
|
|
226
|
+
# Customize action behavior
|
|
227
|
+
config = YdotoolConfig(
|
|
228
|
+
scroll_amount=50, # Larger scroll steps (default: 20)
|
|
229
|
+
wait_duration=2.0, # Longer waits (default: 1.0)
|
|
230
|
+
action_pause=1.0, # More pause between actions (default: 0.5)
|
|
231
|
+
capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
|
|
232
|
+
socket_address="/tmp/ydotool.sock" # Customized Socket address for ydotool (ydotool uses 'YDOTOOL_SOCKET' environment variable by default)
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
action_handler = AsyncYdotoolActionHandler(config=config)
|
|
236
|
+
```
|
|
237
|
+
|
|
198
238
|
## Examples
|
|
199
239
|
|
|
200
240
|
See the [`examples/`](examples/) directory for more usage patterns:
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oagi"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.13.0"
|
|
8
8
|
description = "Official API of OpenAGI Foundation (metapackage with all features)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -16,7 +16,7 @@ authors = [
|
|
|
16
16
|
requires-python = ">= 3.10"
|
|
17
17
|
|
|
18
18
|
dependencies = [
|
|
19
|
-
"oagi-core[desktop,server]==0.
|
|
19
|
+
"oagi-core[desktop,server]==0.13.0",
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
[project.urls]
|
|
@@ -503,18 +503,18 @@ sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6
|
|
|
503
503
|
|
|
504
504
|
[[package]]
|
|
505
505
|
name = "oagi"
|
|
506
|
-
version = "0.
|
|
506
|
+
version = "0.13.0"
|
|
507
507
|
source = { editable = "." }
|
|
508
508
|
dependencies = [
|
|
509
509
|
{ name = "oagi-core", extra = ["desktop", "server"] },
|
|
510
510
|
]
|
|
511
511
|
|
|
512
512
|
[package.metadata]
|
|
513
|
-
requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.12.
|
|
513
|
+
requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.12.1" }]
|
|
514
514
|
|
|
515
515
|
[[package]]
|
|
516
516
|
name = "oagi-core"
|
|
517
|
-
version = "0.12.
|
|
517
|
+
version = "0.12.1"
|
|
518
518
|
source = { registry = "https://pypi.org/simple" }
|
|
519
519
|
dependencies = [
|
|
520
520
|
{ name = "httpx" },
|
|
@@ -522,9 +522,9 @@ dependencies = [
|
|
|
522
522
|
{ name = "pydantic" },
|
|
523
523
|
{ name = "rich" },
|
|
524
524
|
]
|
|
525
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
525
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/70/0977d856ebfb2af41b1d4804f902ef1f8b929de6663ea9a97d879051a6da/oagi_core-0.12.1.tar.gz", hash = "sha256:d04a73849709833b16c55e24edc06f8f17a58d3389ef8849a66c9d7e93183863", size = 297360, upload-time = "2025-12-17T06:46:59.237Z" }
|
|
526
526
|
wheels = [
|
|
527
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
527
|
+
{ url = "https://files.pythonhosted.org/packages/0b/4c/29d774abb3b1dc1cff021021a941caa2926fffd1b9effd0845e9b1fb5afd/oagi_core-0.12.1-py3-none-any.whl", hash = "sha256:32d7638c701990e42d1d4e3c6cee6530b99aed61eea2d36eb5bba1d6cb12ff38", size = 100565, upload-time = "2025-12-17T06:46:57.868Z" },
|
|
528
528
|
]
|
|
529
529
|
|
|
530
530
|
[package.optional-dependencies]
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oagi-core"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.13.0"
|
|
8
8
|
description = "Official API of OpenAGI Foundation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -33,6 +33,7 @@ desktop = [
|
|
|
33
33
|
"pyautogui>=0.9.54",
|
|
34
34
|
"pyobjc-framework-Quartz>=8.0; sys_platform == 'darwin'",
|
|
35
35
|
"pyobjc-framework-ApplicationServices>=8.0; sys_platform == 'darwin'",
|
|
36
|
+
"screeninfo>=0.8.1"
|
|
36
37
|
]
|
|
37
38
|
server = [
|
|
38
39
|
"fastapi[standard]>=0.100.0",
|
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
# Licensed under the MIT License.
|
|
7
7
|
# -----------------------------------------------------------------------------
|
|
8
8
|
import importlib
|
|
9
|
+
import importlib.metadata
|
|
9
10
|
from typing import TYPE_CHECKING
|
|
10
11
|
|
|
12
|
+
__version__ = importlib.metadata.version("oagi-core")
|
|
13
|
+
|
|
11
14
|
from oagi.actor import Actor, AsyncActor, AsyncShortTask, AsyncTask, ShortTask, Task
|
|
12
15
|
from oagi.client import AsyncClient, SyncClient
|
|
13
16
|
from oagi.exceptions import (
|
|
@@ -62,6 +65,22 @@ _LAZY_IMPORTS_DATA: dict[str, tuple[str, str | None, str | None]] = {
|
|
|
62
65
|
"create_app": ("oagi.server.main", "socketio", "server"),
|
|
63
66
|
"ServerConfig": ("oagi.server.config", "pydantic_settings", "server"),
|
|
64
67
|
"sio": ("oagi.server.socketio_server", "socketio", "server"),
|
|
68
|
+
# Wayland handlers
|
|
69
|
+
"AsyncYdotoolActionHandler": (
|
|
70
|
+
"oagi.handler.async_ydotool_action_handler",
|
|
71
|
+
"screeninfo",
|
|
72
|
+
"desktop",
|
|
73
|
+
),
|
|
74
|
+
"YdotoolActionHandler": (
|
|
75
|
+
"oagi.handler.ydotool_action_handler",
|
|
76
|
+
"screeninfo",
|
|
77
|
+
"desktop",
|
|
78
|
+
),
|
|
79
|
+
"YdotoolConfig": (
|
|
80
|
+
"oagi.handler.ydotool_action_handler",
|
|
81
|
+
"screeninfo",
|
|
82
|
+
"desktop",
|
|
83
|
+
),
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
if TYPE_CHECKING:
|
|
@@ -70,12 +89,14 @@ if TYPE_CHECKING:
|
|
|
70
89
|
from oagi.agent.tasker import TaskerAgent
|
|
71
90
|
from oagi.handler.async_pyautogui_action_handler import AsyncPyautoguiActionHandler
|
|
72
91
|
from oagi.handler.async_screenshot_maker import AsyncScreenshotMaker
|
|
92
|
+
from oagi.handler.async_ydotool_action_handler import AsyncYdotoolActionHandler
|
|
73
93
|
from oagi.handler.pil_image import PILImage
|
|
74
94
|
from oagi.handler.pyautogui_action_handler import (
|
|
75
95
|
PyautoguiActionHandler,
|
|
76
96
|
PyautoguiConfig,
|
|
77
97
|
)
|
|
78
98
|
from oagi.handler.screenshot_maker import ScreenshotMaker
|
|
99
|
+
from oagi.handler.ydotool_action_handler import YdotoolActionHandler, YdotoolConfig
|
|
79
100
|
from oagi.server.config import ServerConfig
|
|
80
101
|
from oagi.server.main import create_app
|
|
81
102
|
from oagi.server.socketio_server import sio
|
|
@@ -98,6 +119,8 @@ def __dir__() -> list[str]:
|
|
|
98
119
|
|
|
99
120
|
|
|
100
121
|
__all__ = [
|
|
122
|
+
# Version
|
|
123
|
+
"__version__",
|
|
101
124
|
# Core sync classes
|
|
102
125
|
"Actor",
|
|
103
126
|
"AsyncActor",
|
|
@@ -143,4 +166,8 @@ __all__ = [
|
|
|
143
166
|
"create_app",
|
|
144
167
|
"ServerConfig",
|
|
145
168
|
"sio",
|
|
169
|
+
# Lazy imports - Wayland handler classes
|
|
170
|
+
"AsyncYdotoolActionHandler",
|
|
171
|
+
"YdotoolActionHandler",
|
|
172
|
+
"YdotoolConfig",
|
|
146
173
|
]
|
|
@@ -206,14 +206,25 @@ def _warn_missing_permissions() -> None:
|
|
|
206
206
|
|
|
207
207
|
def run_agent(args: argparse.Namespace) -> None:
|
|
208
208
|
# Check if desktop extras are installed
|
|
209
|
-
check_optional_dependency("pyautogui", "Agent execution", "desktop")
|
|
210
209
|
check_optional_dependency("PIL", "Agent execution", "desktop")
|
|
211
210
|
|
|
212
|
-
|
|
213
|
-
_warn_missing_permissions()
|
|
214
|
-
|
|
215
|
-
from oagi import AsyncPyautoguiActionHandler, AsyncScreenshotMaker # noqa: PLC0415
|
|
211
|
+
from oagi import AsyncScreenshotMaker # noqa: PLC0415
|
|
216
212
|
from oagi.agent import create_agent # noqa: PLC0415
|
|
213
|
+
from oagi.handler.wayland_support import is_wayland_display_server # noqa: PLC0415
|
|
214
|
+
|
|
215
|
+
# Select appropriate action handler based on display server
|
|
216
|
+
if is_wayland_display_server():
|
|
217
|
+
check_optional_dependency("screeninfo", "Agent execution (Wayland)", "desktop")
|
|
218
|
+
from oagi import AsyncYdotoolActionHandler # noqa: PLC0415
|
|
219
|
+
|
|
220
|
+
action_handler = AsyncYdotoolActionHandler()
|
|
221
|
+
else:
|
|
222
|
+
check_optional_dependency("pyautogui", "Agent execution", "desktop")
|
|
223
|
+
# Warn about missing macOS permissions (non-blocking)
|
|
224
|
+
_warn_missing_permissions()
|
|
225
|
+
from oagi import AsyncPyautoguiActionHandler # noqa: PLC0415
|
|
226
|
+
|
|
227
|
+
action_handler = AsyncPyautoguiActionHandler()
|
|
217
228
|
|
|
218
229
|
# Get configuration
|
|
219
230
|
api_key = args.oagi_api_key or os.getenv("OAGI_API_KEY")
|
|
@@ -266,8 +277,7 @@ def run_agent(args: argparse.Namespace) -> None:
|
|
|
266
277
|
# Create agent
|
|
267
278
|
agent = create_agent(**agent_kwargs)
|
|
268
279
|
|
|
269
|
-
# Create
|
|
270
|
-
action_handler = AsyncPyautoguiActionHandler()
|
|
280
|
+
# Create image provider
|
|
271
281
|
image_provider = AsyncScreenshotMaker()
|
|
272
282
|
|
|
273
283
|
if args.instruction:
|
|
@@ -19,6 +19,7 @@ from ..constants import (
|
|
|
19
19
|
HTTP_CLIENT_TIMEOUT,
|
|
20
20
|
)
|
|
21
21
|
from ..logging import get_logger
|
|
22
|
+
from ..platform_info import get_sdk_headers
|
|
22
23
|
from ..types import Image
|
|
23
24
|
from ..types.models import GenerateResponse, UploadFileResponse, Usage
|
|
24
25
|
from ..types.models.step import Step
|
|
@@ -54,17 +55,21 @@ class AsyncClient(BaseClient[httpx.AsyncClient]):
|
|
|
54
55
|
):
|
|
55
56
|
super().__init__(base_url, api_key, max_retries)
|
|
56
57
|
|
|
58
|
+
# Get SDK headers for all clients
|
|
59
|
+
sdk_headers = get_sdk_headers()
|
|
60
|
+
|
|
57
61
|
# OpenAI client for chat completions (with retries)
|
|
58
62
|
self.openai_client = AsyncOpenAI(
|
|
59
63
|
api_key=self.api_key,
|
|
60
64
|
base_url=f"{self.base_url}/v1",
|
|
61
65
|
max_retries=self.max_retries,
|
|
66
|
+
default_headers=sdk_headers,
|
|
62
67
|
)
|
|
63
68
|
|
|
64
69
|
# httpx clients for S3 uploads and other endpoints (with retries)
|
|
65
70
|
transport = AsyncHTTPTransport(retries=self.max_retries)
|
|
66
71
|
self.http_client = httpx.AsyncClient(
|
|
67
|
-
transport=transport, base_url=self.base_url
|
|
72
|
+
transport=transport, base_url=self.base_url, headers=sdk_headers
|
|
68
73
|
)
|
|
69
74
|
self.upload_client = httpx.AsyncClient(
|
|
70
75
|
transport=transport, timeout=HTTP_CLIENT_TIMEOUT
|
|
@@ -29,6 +29,7 @@ from ..exceptions import (
|
|
|
29
29
|
ValidationError,
|
|
30
30
|
)
|
|
31
31
|
from ..logging import get_logger
|
|
32
|
+
from ..platform_info import get_sdk_headers
|
|
32
33
|
from ..types.models import (
|
|
33
34
|
ErrorResponse,
|
|
34
35
|
GenerateResponse,
|
|
@@ -73,7 +74,7 @@ class BaseClient(Generic[HttpClientT]):
|
|
|
73
74
|
logger.info(f"Client initialized with base_url: {self.base_url}")
|
|
74
75
|
|
|
75
76
|
def _build_headers(self, api_version: str | None = None) -> dict[str, str]:
|
|
76
|
-
headers
|
|
77
|
+
headers = get_sdk_headers()
|
|
77
78
|
if api_version:
|
|
78
79
|
headers["x-api-version"] = api_version
|
|
79
80
|
if self.api_key:
|
|
@@ -19,6 +19,7 @@ from ..constants import (
|
|
|
19
19
|
HTTP_CLIENT_TIMEOUT,
|
|
20
20
|
)
|
|
21
21
|
from ..logging import get_logger
|
|
22
|
+
from ..platform_info import get_sdk_headers
|
|
22
23
|
from ..types import Image
|
|
23
24
|
from ..types.models import GenerateResponse, UploadFileResponse, Usage
|
|
24
25
|
from ..types.models.step import Step
|
|
@@ -54,16 +55,22 @@ class SyncClient(BaseClient[httpx.Client]):
|
|
|
54
55
|
):
|
|
55
56
|
super().__init__(base_url, api_key, max_retries)
|
|
56
57
|
|
|
58
|
+
# Get SDK headers for all clients
|
|
59
|
+
sdk_headers = get_sdk_headers()
|
|
60
|
+
|
|
57
61
|
# OpenAI client for chat completions (with retries)
|
|
58
62
|
self.openai_client = OpenAI(
|
|
59
63
|
api_key=self.api_key,
|
|
60
64
|
base_url=f"{self.base_url}/v1",
|
|
61
65
|
max_retries=self.max_retries,
|
|
66
|
+
default_headers=sdk_headers,
|
|
62
67
|
)
|
|
63
68
|
|
|
64
69
|
# httpx clients for S3 uploads and other endpoints (with retries)
|
|
65
70
|
transport = HTTPTransport(retries=self.max_retries)
|
|
66
|
-
self.http_client = httpx.Client(
|
|
71
|
+
self.http_client = httpx.Client(
|
|
72
|
+
transport=transport, base_url=self.base_url, headers=sdk_headers
|
|
73
|
+
)
|
|
67
74
|
self.upload_client = httpx.Client(
|
|
68
75
|
transport=transport, timeout=HTTP_CLIENT_TIMEOUT
|
|
69
76
|
)
|
|
@@ -18,17 +18,22 @@ _LAZY_IMPORTS: dict[str, str] = {
|
|
|
18
18
|
"PyautoguiActionHandler": "oagi.handler.pyautogui_action_handler",
|
|
19
19
|
"PyautoguiConfig": "oagi.handler.pyautogui_action_handler",
|
|
20
20
|
"ScreenshotMaker": "oagi.handler.screenshot_maker",
|
|
21
|
+
"AsyncYdotoolActionHandler": "oagi.handler.async_ydotool_action_handler",
|
|
22
|
+
"YdotoolActionHandler": "oagi.handler.ydotool_action_handler",
|
|
23
|
+
"YdotoolConfig": "oagi.handler.ydotool_action_handler",
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
if TYPE_CHECKING:
|
|
24
27
|
from oagi.handler.async_pyautogui_action_handler import AsyncPyautoguiActionHandler
|
|
25
28
|
from oagi.handler.async_screenshot_maker import AsyncScreenshotMaker
|
|
29
|
+
from oagi.handler.async_ydotool_action_handler import AsyncYdotoolActionHandler
|
|
26
30
|
from oagi.handler.pil_image import PILImage
|
|
27
31
|
from oagi.handler.pyautogui_action_handler import (
|
|
28
32
|
PyautoguiActionHandler,
|
|
29
33
|
PyautoguiConfig,
|
|
30
34
|
)
|
|
31
35
|
from oagi.handler.screenshot_maker import ScreenshotMaker
|
|
36
|
+
from oagi.handler.ydotool_action_handler import YdotoolActionHandler, YdotoolConfig
|
|
32
37
|
|
|
33
38
|
|
|
34
39
|
def __getattr__(name: str):
|
|
@@ -52,4 +57,7 @@ __all__ = [
|
|
|
52
57
|
"ScreenshotMaker",
|
|
53
58
|
"AsyncScreenshotMaker",
|
|
54
59
|
"reset_handler",
|
|
60
|
+
"YdotoolConfig",
|
|
61
|
+
"YdotoolActionHandler",
|
|
62
|
+
"AsyncYdotoolActionHandler",
|
|
55
63
|
]
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) OpenAGI Foundation
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# This file is part of the official API project.
|
|
6
|
+
# Licensed under the MIT License.
|
|
7
|
+
# -----------------------------------------------------------------------------
|
|
8
|
+
"""
|
|
9
|
+
Taken from /usr/include/linux/input-event-codes.h
|
|
10
|
+
|
|
11
|
+
The keys supported in this mapping are the same as the keys supported in pyautogui.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
KEYCODE_MAP = {
|
|
15
|
+
# Letters
|
|
16
|
+
"a": 30,
|
|
17
|
+
"s": 31,
|
|
18
|
+
"d": 32,
|
|
19
|
+
"f": 33,
|
|
20
|
+
"h": 35,
|
|
21
|
+
"g": 34,
|
|
22
|
+
"z": 44,
|
|
23
|
+
"x": 45,
|
|
24
|
+
"c": 46,
|
|
25
|
+
"v": 47,
|
|
26
|
+
"b": 48,
|
|
27
|
+
"q": 16,
|
|
28
|
+
"w": 17,
|
|
29
|
+
"e": 18,
|
|
30
|
+
"r": 19,
|
|
31
|
+
"y": 21,
|
|
32
|
+
"t": 20,
|
|
33
|
+
"o": 24,
|
|
34
|
+
"u": 22,
|
|
35
|
+
"i": 23,
|
|
36
|
+
"p": 25,
|
|
37
|
+
"l": 38,
|
|
38
|
+
"j": 36,
|
|
39
|
+
"k": 37,
|
|
40
|
+
"n": 49,
|
|
41
|
+
"m": 50,
|
|
42
|
+
# Numbers and shifted symbols
|
|
43
|
+
"1": 2,
|
|
44
|
+
"!": 2,
|
|
45
|
+
"2": 3,
|
|
46
|
+
"@": 3,
|
|
47
|
+
"3": 4,
|
|
48
|
+
"#": 4,
|
|
49
|
+
"4": 5,
|
|
50
|
+
"$": 5,
|
|
51
|
+
"5": 6,
|
|
52
|
+
"%": 6,
|
|
53
|
+
"6": 7,
|
|
54
|
+
"^": 7,
|
|
55
|
+
"7": 8,
|
|
56
|
+
"&": 8,
|
|
57
|
+
"8": 9,
|
|
58
|
+
"*": 9,
|
|
59
|
+
"9": 10,
|
|
60
|
+
"(": 10,
|
|
61
|
+
"0": 11,
|
|
62
|
+
")": 11,
|
|
63
|
+
# Punctuation and symbols
|
|
64
|
+
"-": 12,
|
|
65
|
+
"_": 12, # KEY_MINUS
|
|
66
|
+
"=": 13,
|
|
67
|
+
"+": 13, # KEY_EQUAL
|
|
68
|
+
"[": 26,
|
|
69
|
+
"{": 26, # KEY_LEFTBRACE
|
|
70
|
+
"]": 27,
|
|
71
|
+
"}": 27, # KEY_RIGHTBRACE
|
|
72
|
+
";": 39,
|
|
73
|
+
":": 39, # KEY_SEMICOLON
|
|
74
|
+
"'": 40,
|
|
75
|
+
'"': 40, # KEY_APOSTROPHE
|
|
76
|
+
"`": 41,
|
|
77
|
+
"~": 41, # KEY_GRAVE
|
|
78
|
+
"\\": 43,
|
|
79
|
+
"|": 43, # KEY_BACKSLASH
|
|
80
|
+
",": 51,
|
|
81
|
+
"<": 51, # KEY_COMMA
|
|
82
|
+
".": 52,
|
|
83
|
+
">": 52, # KEY_DOT
|
|
84
|
+
"/": 53,
|
|
85
|
+
"?": 53, # KEY_SLASH
|
|
86
|
+
# Whitespace
|
|
87
|
+
" ": 57,
|
|
88
|
+
"space": 57,
|
|
89
|
+
"\t": 15,
|
|
90
|
+
"tab": 15,
|
|
91
|
+
# Enter / Backspace / Esc
|
|
92
|
+
"\r": 28,
|
|
93
|
+
"\n": 28,
|
|
94
|
+
"enter": 28,
|
|
95
|
+
"return": 28,
|
|
96
|
+
"backspace": 14,
|
|
97
|
+
"\b": 14,
|
|
98
|
+
"esc": 1,
|
|
99
|
+
"escape": 1,
|
|
100
|
+
# Modifiers
|
|
101
|
+
"shift": 42,
|
|
102
|
+
"shiftleft": 42,
|
|
103
|
+
"shiftright": 54,
|
|
104
|
+
"capslock": 58,
|
|
105
|
+
"ctrl": 29,
|
|
106
|
+
"ctrlleft": 29,
|
|
107
|
+
"ctrlright": 97,
|
|
108
|
+
"alt": 56,
|
|
109
|
+
"altleft": 56,
|
|
110
|
+
"option": 56,
|
|
111
|
+
"optionleft": 56,
|
|
112
|
+
"optionright": 100,
|
|
113
|
+
"command": 125, # map to KEY_LEFTMETA
|
|
114
|
+
"fn": 464, # KEY_FN (0x1d0)
|
|
115
|
+
# Function keys
|
|
116
|
+
"f1": 59,
|
|
117
|
+
"f2": 60,
|
|
118
|
+
"f3": 61,
|
|
119
|
+
"f4": 62,
|
|
120
|
+
"f5": 63,
|
|
121
|
+
"f6": 64,
|
|
122
|
+
"f7": 65,
|
|
123
|
+
"f8": 66,
|
|
124
|
+
"f9": 67,
|
|
125
|
+
"f10": 68,
|
|
126
|
+
"f11": 87,
|
|
127
|
+
"f12": 88,
|
|
128
|
+
"f13": 183,
|
|
129
|
+
"f14": 184,
|
|
130
|
+
"f15": 185,
|
|
131
|
+
"f16": 186,
|
|
132
|
+
"f17": 187,
|
|
133
|
+
"f18": 188,
|
|
134
|
+
"f19": 189,
|
|
135
|
+
"f20": 190,
|
|
136
|
+
# Navigation
|
|
137
|
+
"home": 102,
|
|
138
|
+
"end": 107,
|
|
139
|
+
"pageup": 104,
|
|
140
|
+
"pgup": 104,
|
|
141
|
+
"pagedown": 109,
|
|
142
|
+
"pgdn": 109,
|
|
143
|
+
"left": 105,
|
|
144
|
+
"right": 106,
|
|
145
|
+
"up": 103,
|
|
146
|
+
"down": 108,
|
|
147
|
+
"del": 111,
|
|
148
|
+
"delete": 111,
|
|
149
|
+
# Media
|
|
150
|
+
"volumeup": 115,
|
|
151
|
+
"volumedown": 114,
|
|
152
|
+
"volumemute": 113,
|
|
153
|
+
# Locale-specific keys
|
|
154
|
+
"yen": 124, # KEY_YEN
|
|
155
|
+
"eisu": 85, # mapped to KEY_ZENKAKUHANKAKU (common JIS toggle)
|
|
156
|
+
"kana": 90, # KEY_KATAKANA
|
|
157
|
+
"help": 138, # KEY_HELP
|
|
158
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) OpenAGI Foundation
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
#
|
|
5
|
+
# This file is part of the official API project.
|
|
6
|
+
# Licensed under the MIT License.
|
|
7
|
+
# -----------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
|
|
11
|
+
from ..types import Action
|
|
12
|
+
from .ydotool_action_handler import YdotoolActionHandler, YdotoolConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AsyncYdotoolActionHandler:
|
|
16
|
+
"""
|
|
17
|
+
Async wrapper for YdotoolActionHandler that runs actions in a thread pool.
|
|
18
|
+
|
|
19
|
+
This allows Ydotool operations to be non-blocking in async contexts,
|
|
20
|
+
enabling concurrent execution of other async tasks while GUI actions are performed.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, config: YdotoolConfig | None = None):
|
|
24
|
+
"""Initialize with optional configuration.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
config: YdotoolConfig instance for customizing behavior
|
|
28
|
+
"""
|
|
29
|
+
self.config = config or YdotoolConfig()
|
|
30
|
+
self.sync_handler = YdotoolActionHandler(config=self.config)
|
|
31
|
+
|
|
32
|
+
def reset(self):
|
|
33
|
+
"""Reset handler state.
|
|
34
|
+
|
|
35
|
+
Delegates to the underlying synchronous handler's reset method.
|
|
36
|
+
Called at automation start/end and when FINISH action is received.
|
|
37
|
+
"""
|
|
38
|
+
self.sync_handler.reset()
|
|
39
|
+
|
|
40
|
+
async def __call__(self, actions: list[Action]) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Execute actions asynchronously using a thread pool executor.
|
|
43
|
+
|
|
44
|
+
This prevents PyAutoGUI operations from blocking the async event loop,
|
|
45
|
+
allowing other coroutines to run while GUI actions are being performed.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
actions: List of actions to execute
|
|
49
|
+
"""
|
|
50
|
+
loop = asyncio.get_event_loop()
|
|
51
|
+
# Run the synchronous handler in a thread pool to avoid blocking
|
|
52
|
+
await loop.run_in_executor(None, self.sync_handler, actions)
|
|
@@ -10,6 +10,8 @@ import io
|
|
|
10
10
|
|
|
11
11
|
from ..exceptions import check_optional_dependency
|
|
12
12
|
from ..types.models.image_config import ImageConfig
|
|
13
|
+
from .wayland_support import is_wayland_display_server
|
|
14
|
+
from .wayland_support import screenshot as wayland_screenshot
|
|
13
15
|
|
|
14
16
|
check_optional_dependency("PIL", "PILImage", "desktop")
|
|
15
17
|
from PIL import Image as PILImageLib # noqa: E402
|
|
@@ -39,6 +41,10 @@ class PILImage:
|
|
|
39
41
|
@classmethod
|
|
40
42
|
def from_screenshot(cls, config: ImageConfig | None = None) -> "PILImage":
|
|
41
43
|
"""Create PILImage from screenshot."""
|
|
44
|
+
# Use flameshot by default in Wayland display environment
|
|
45
|
+
if is_wayland_display_server():
|
|
46
|
+
return cls(wayland_screenshot(), config)
|
|
47
|
+
|
|
42
48
|
# Lazy import to avoid DISPLAY issues in headless environments
|
|
43
49
|
check_optional_dependency("pyautogui", "PILImage.from_screenshot()", "desktop")
|
|
44
50
|
import pyautogui # noqa: PLC0415
|