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.
Files changed (129) hide show
  1. {oagi_core-0.12.1 → oagi_core-0.13.0}/PKG-INFO +42 -1
  2. {oagi_core-0.12.1 → oagi_core-0.13.0}/README.md +40 -0
  3. {oagi_core-0.12.1 → oagi_core-0.13.0}/metapackage/pyproject.toml +2 -2
  4. {oagi_core-0.12.1 → oagi_core-0.13.0}/metapackage/uv.lock +5 -5
  5. {oagi_core-0.12.1 → oagi_core-0.13.0}/pyproject.toml +2 -1
  6. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/__init__.py +27 -0
  7. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/agent.py +17 -7
  8. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/async_.py +6 -1
  9. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/base.py +2 -1
  10. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/sync.py +8 -1
  11. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/__init__.py +8 -0
  12. oagi_core-0.13.0/src/oagi/handler/_ydotool.py +158 -0
  13. oagi_core-0.13.0/src/oagi/handler/async_ydotool_action_handler.py +52 -0
  14. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/pil_image.py +6 -0
  15. oagi_core-0.13.0/src/oagi/handler/wayland_support.py +219 -0
  16. oagi_core-0.13.0/src/oagi/handler/ydotool_action_handler.py +226 -0
  17. oagi_core-0.13.0/src/oagi/platform_info.py +51 -0
  18. {oagi_core-0.12.1 → oagi_core-0.13.0}/uv.lock +31 -1
  19. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  20. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  21. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  22. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  23. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/workflows/ci.yml +0 -0
  24. {oagi_core-0.12.1 → oagi_core-0.13.0}/.github/workflows/release.yml +0 -0
  25. {oagi_core-0.12.1 → oagi_core-0.13.0}/.gitignore +0 -0
  26. {oagi_core-0.12.1 → oagi_core-0.13.0}/.python-version +0 -0
  27. {oagi_core-0.12.1 → oagi_core-0.13.0}/CONTRIBUTING.md +0 -0
  28. {oagi_core-0.12.1 → oagi_core-0.13.0}/LICENSE +0 -0
  29. {oagi_core-0.12.1 → oagi_core-0.13.0}/Makefile +0 -0
  30. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/async_google_weather.py +0 -0
  31. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/execute_task_auto.py +0 -0
  32. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/execute_task_manual.py +0 -0
  33. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/google_weather.py +0 -0
  34. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/openai_agent_loop_example.py +0 -0
  35. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/screenshot_with_config.py +0 -0
  36. {oagi_core-0.12.1 → oagi_core-0.13.0}/examples/tasker_agent_example.py +0 -0
  37. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/__init__.py +0 -0
  38. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/async_.py +0 -0
  39. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/async_short.py +0 -0
  40. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/base.py +0 -0
  41. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/short.py +0 -0
  42. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/actor/sync.py +0 -0
  43. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/__init__.py +0 -0
  44. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/default.py +0 -0
  45. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/factories.py +0 -0
  46. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/__init__.py +0 -0
  47. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/agent_observer.py +0 -0
  48. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/events.py +0 -0
  49. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/exporters.py +0 -0
  50. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/protocol.py +0 -0
  51. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/observer/report_template.html +0 -0
  52. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/protocol.py +0 -0
  53. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/registry.py +0 -0
  54. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/__init__.py +0 -0
  55. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/memory.py +0 -0
  56. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/models.py +0 -0
  57. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/planner.py +0 -0
  58. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/taskee_agent.py +0 -0
  59. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/agent/tasker/tasker_agent.py +0 -0
  60. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/__init__.py +0 -0
  61. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/display.py +0 -0
  62. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/main.py +0 -0
  63. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/server.py +0 -0
  64. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/tracking.py +0 -0
  65. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/cli/utils.py +0 -0
  66. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/client/__init__.py +0 -0
  67. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/constants.py +0 -0
  68. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/exceptions.py +0 -0
  69. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/_macos.py +0 -0
  70. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/_windows.py +0 -0
  71. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/async_pyautogui_action_handler.py +0 -0
  72. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/async_screenshot_maker.py +0 -0
  73. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/capslock_manager.py +0 -0
  74. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/pyautogui_action_handler.py +0 -0
  75. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/screenshot_maker.py +0 -0
  76. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/handler/utils.py +0 -0
  77. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/logging.py +0 -0
  78. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/__init__.py +0 -0
  79. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/agent_wrappers.py +0 -0
  80. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/config.py +0 -0
  81. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/main.py +0 -0
  82. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/models.py +0 -0
  83. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/session_store.py +0 -0
  84. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/server/socketio_server.py +0 -0
  85. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/task/__init__.py +0 -0
  86. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/__init__.py +0 -0
  87. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/action_handler.py +0 -0
  88. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/async_action_handler.py +0 -0
  89. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/async_image_provider.py +0 -0
  90. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/image.py +0 -0
  91. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/image_provider.py +0 -0
  92. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/__init__.py +0 -0
  93. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/action.py +0 -0
  94. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/client.py +0 -0
  95. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/image_config.py +0 -0
  96. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/models/step.py +0 -0
  97. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/step_observer.py +0 -0
  98. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/types/url.py +0 -0
  99. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/__init__.py +0 -0
  100. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/output_parser.py +0 -0
  101. {oagi_core-0.12.1 → oagi_core-0.13.0}/src/oagi/utils/prompt_builder.py +0 -0
  102. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/__init__.py +0 -0
  103. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/conftest.py +0 -0
  104. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_action_parsing.py +0 -0
  105. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_actor.py +0 -0
  106. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent/test_agent_wrappers.py +0 -0
  107. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent/test_default_agent.py +0 -0
  108. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_agent_registry.py +0 -0
  109. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_actor.py +0 -0
  110. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_client.py +0 -0
  111. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_async_handlers.py +0 -0
  112. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_cli.py +0 -0
  113. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_logging.py +0 -0
  114. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_mac_double_click.py +0 -0
  115. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_observer.py +0 -0
  116. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_pil_image.py +0 -0
  117. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_planner.py +0 -0
  118. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_planner_memory.py +0 -0
  119. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_pyautogui_action_handler.py +0 -0
  120. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_screenshot_maker.py +0 -0
  121. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/__init__.py +0 -0
  122. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_config.py +0 -0
  123. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_session_store.py +0 -0
  124. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_server/test_socketio_integration.py +0 -0
  125. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_sync_client.py +0 -0
  126. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_taskee_agent.py +0 -0
  127. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/test_tasker_agent.py +0 -0
  128. {oagi_core-0.12.1 → oagi_core-0.13.0}/tests/utils/__init__.py +0 -0
  129. {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.12.1
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.12.1"
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.12.1",
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.12.1"
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.0" }]
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.0"
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/5f/20/431fe40c681194886fa51b841929a6be4d614409817f048ab88fab1ef4f8/oagi_core-0.12.0.tar.gz", hash = "sha256:3ffd93f217bac5357fd28442a65c679a3b1891e52419f833dd7d2bbd48015d7a", size = 286697, upload-time = "2025-12-11T10:56:26.121Z" }
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/6f/fb/4474f6f2dcb4ee9ac1699d437b5b133be695a919108b50e9ace92e763e9f/oagi_core-0.12.0-py3-none-any.whl", hash = "sha256:37c67c2b96a13166dd4fa89828e967fdd23f0eb871ec1b22acef8bf4ce777c8a", size = 99904, upload-time = "2025-12-11T10:56:24.684Z" },
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.12.1"
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
- # Warn about missing macOS permissions (non-blocking)
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 handlers
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: dict[str, str] = {}
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(transport=transport, base_url=self.base_url)
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