oagi-core 0.14.0__tar.gz → 0.14.1__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 (131) hide show
  1. {oagi_core-0.14.0 → oagi_core-0.14.1}/PKG-INFO +14 -10
  2. {oagi_core-0.14.0 → oagi_core-0.14.1}/README.md +13 -9
  3. {oagi_core-0.14.0 → oagi_core-0.14.1}/metapackage/pyproject.toml +2 -2
  4. {oagi_core-0.14.0 → oagi_core-0.14.1}/metapackage/uv.lock +15 -5
  5. {oagi_core-0.14.0 → oagi_core-0.14.1}/pyproject.toml +1 -1
  6. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/default.py +4 -6
  7. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/taskee_agent.py +4 -6
  8. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/async_pyautogui_action_handler.py +2 -1
  9. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/pyautogui_action_handler.py +11 -0
  10. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/utils.py +14 -0
  11. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/ydotool_action_handler.py +11 -0
  12. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_mac_double_click.py +6 -3
  13. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_pyautogui_action_handler.py +47 -19
  14. {oagi_core-0.14.0 → oagi_core-0.14.1}/uv.lock +1 -1
  15. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  16. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  17. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  18. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  19. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/workflows/ci.yml +0 -0
  20. {oagi_core-0.14.0 → oagi_core-0.14.1}/.github/workflows/release.yml +0 -0
  21. {oagi_core-0.14.0 → oagi_core-0.14.1}/.gitignore +0 -0
  22. {oagi_core-0.14.0 → oagi_core-0.14.1}/.python-version +0 -0
  23. {oagi_core-0.14.0 → oagi_core-0.14.1}/CONTRIBUTING.md +0 -0
  24. {oagi_core-0.14.0 → oagi_core-0.14.1}/LICENSE +0 -0
  25. {oagi_core-0.14.0 → oagi_core-0.14.1}/Makefile +0 -0
  26. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/async_google_weather.py +0 -0
  27. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/execute_task_auto.py +0 -0
  28. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/execute_task_manual.py +0 -0
  29. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/google_weather.py +0 -0
  30. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/multi_screen_execution.py +0 -0
  31. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/openai_agent_loop_example.py +0 -0
  32. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/screenshot_with_config.py +0 -0
  33. {oagi_core-0.14.0 → oagi_core-0.14.1}/examples/tasker_agent_example.py +0 -0
  34. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/__init__.py +0 -0
  35. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/__init__.py +0 -0
  36. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/async_.py +0 -0
  37. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/async_short.py +0 -0
  38. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/base.py +0 -0
  39. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/short.py +0 -0
  40. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/actor/sync.py +0 -0
  41. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/__init__.py +0 -0
  42. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/factories.py +0 -0
  43. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/__init__.py +0 -0
  44. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/agent_observer.py +0 -0
  45. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/events.py +0 -0
  46. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/exporters.py +0 -0
  47. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/protocol.py +0 -0
  48. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/observer/report_template.html +0 -0
  49. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/protocol.py +0 -0
  50. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/registry.py +0 -0
  51. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/__init__.py +0 -0
  52. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/memory.py +0 -0
  53. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/models.py +0 -0
  54. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/planner.py +0 -0
  55. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/agent/tasker/tasker_agent.py +0 -0
  56. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/__init__.py +0 -0
  57. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/agent.py +0 -0
  58. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/display.py +0 -0
  59. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/main.py +0 -0
  60. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/server.py +0 -0
  61. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/tracking.py +0 -0
  62. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/cli/utils.py +0 -0
  63. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/client/__init__.py +0 -0
  64. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/client/async_.py +0 -0
  65. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/client/base.py +0 -0
  66. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/client/sync.py +0 -0
  67. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/constants.py +0 -0
  68. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/exceptions.py +0 -0
  69. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/__init__.py +0 -0
  70. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/_macos.py +0 -0
  71. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/_windows.py +0 -0
  72. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/_ydotool.py +0 -0
  73. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/async_screenshot_maker.py +0 -0
  74. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/async_ydotool_action_handler.py +0 -0
  75. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/capslock_manager.py +0 -0
  76. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/pil_image.py +0 -0
  77. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/screen_manager.py +0 -0
  78. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/screenshot_maker.py +0 -0
  79. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/handler/wayland_support.py +0 -0
  80. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/logging.py +0 -0
  81. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/platform_info.py +0 -0
  82. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/__init__.py +0 -0
  83. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/agent_wrappers.py +0 -0
  84. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/config.py +0 -0
  85. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/main.py +0 -0
  86. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/models.py +0 -0
  87. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/session_store.py +0 -0
  88. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/server/socketio_server.py +0 -0
  89. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/task/__init__.py +0 -0
  90. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/__init__.py +0 -0
  91. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/action_handler.py +0 -0
  92. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/async_action_handler.py +0 -0
  93. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/async_image_provider.py +0 -0
  94. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/image.py +0 -0
  95. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/image_provider.py +0 -0
  96. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/models/__init__.py +0 -0
  97. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/models/action.py +0 -0
  98. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/models/client.py +0 -0
  99. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/models/image_config.py +0 -0
  100. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/models/step.py +0 -0
  101. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/step_observer.py +0 -0
  102. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/types/url.py +0 -0
  103. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/utils/__init__.py +0 -0
  104. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/utils/output_parser.py +0 -0
  105. {oagi_core-0.14.0 → oagi_core-0.14.1}/src/oagi/utils/prompt_builder.py +0 -0
  106. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/__init__.py +0 -0
  107. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/conftest.py +0 -0
  108. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_action_parsing.py +0 -0
  109. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_actor.py +0 -0
  110. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_agent/test_agent_wrappers.py +0 -0
  111. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_agent/test_default_agent.py +0 -0
  112. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_agent_registry.py +0 -0
  113. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_async_actor.py +0 -0
  114. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_async_client.py +0 -0
  115. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_async_handlers.py +0 -0
  116. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_cli.py +0 -0
  117. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_logging.py +0 -0
  118. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_observer.py +0 -0
  119. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_pil_image.py +0 -0
  120. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_planner.py +0 -0
  121. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_planner_memory.py +0 -0
  122. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_screenshot_maker.py +0 -0
  123. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_server/__init__.py +0 -0
  124. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_server/test_config.py +0 -0
  125. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_server/test_session_store.py +0 -0
  126. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_server/test_socketio_integration.py +0 -0
  127. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_sync_client.py +0 -0
  128. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_taskee_agent.py +0 -0
  129. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/test_tasker_agent.py +0 -0
  130. {oagi_core-0.14.0 → oagi_core-0.14.1}/tests/utils/__init__.py +0 -0
  131. {oagi_core-0.14.0 → oagi_core-0.14.1}/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.14.0
3
+ Version: 0.14.1
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)
@@ -108,12 +108,15 @@ from oagi import AsyncPyautoguiActionHandler, PyautoguiConfig
108
108
 
109
109
  # Customize action behavior
110
110
  config = PyautoguiConfig(
111
- drag_duration=1.0, # Slower drags for precision (default: 0.5)
112
- scroll_amount=50, # Larger scroll steps (default: 30)
113
- wait_duration=2.0, # Longer waits (default: 1.0)
114
- action_pause=0.2, # More pause between actions (default: 0.1)
115
- hotkey_interval=0.1, # Interval between keys in hotkey combinations (default: 0.1)
116
- capslock_mode="session" # Caps lock mode: 'session' or 'system' (default: 'session')
111
+ drag_duration=1.0, # Slower drags for precision (default: 0.5)
112
+ scroll_amount=50, # Larger scroll steps (default: 2 on macOS, 100 on others)
113
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
114
+ action_pause=0.2, # Pause between PyAutoGUI calls (default: 0.1)
115
+ hotkey_interval=0.1, # Interval between keys in hotkey combos (default: 0.1)
116
+ capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
117
+ macos_ctrl_to_cmd=True, # Replace ctrl with cmd on macOS (default: True)
118
+ click_pre_delay=0.1, # Delay after move before click (default: 0.1)
119
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
117
120
  )
118
121
 
119
122
  action_handler = AsyncPyautoguiActionHandler(config=config)
@@ -233,10 +236,11 @@ from oagi import AsyncYdotoolActionHandler, YdotoolConfig
233
236
  # Customize action behavior
234
237
  config = YdotoolConfig(
235
238
  scroll_amount=50, # Larger scroll steps (default: 20)
236
- wait_duration=2.0, # Longer waits (default: 1.0)
237
- action_pause=1.0, # More pause between actions (default: 0.5)
239
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
240
+ action_pause=1.0, # Pause between Ydotool calls (default: 0.5)
238
241
  capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
239
- socket_address="/tmp/ydotool.sock" # Customized Socket address for ydotool (ydotool uses 'YDOTOOL_SOCKET' environment variable by default)
242
+ socket_address="/tmp/ydotool.sock", # Custom socket address (default: YDOTOOL_SOCKET env var)
243
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
240
244
  )
241
245
 
242
246
  action_handler = AsyncYdotoolActionHandler(config=config)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oagi"
7
- version = "0.14.0"
7
+ version = "0.14.1"
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.14.0",
19
+ "oagi-core[desktop,server]==0.14.1",
20
20
  ]
21
21
 
22
22
  [project.urls]
@@ -516,20 +516,29 @@ dependencies = [
516
516
  ]
517
517
  sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6381c1dcae6f4159a7f72349e414ed19cfbbd1817173/MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7", size = 10850, upload-time = "2020-03-27T21:20:10.136Z" }
518
518
 
519
+ [[package]]
520
+ name = "mss"
521
+ version = "10.1.0"
522
+ source = { registry = "https://pypi.org/simple" }
523
+ sdist = { url = "https://files.pythonhosted.org/packages/40/ca/49b67437a8c46d9732c9c274d7b1fc0c181cfe290d699a0c5e94701dfe79/mss-10.1.0.tar.gz", hash = "sha256:7182baf7ee16ca569e2804028b6ab9bcbf6be5c46fc2880840f33b513b9cb4f8", size = 84200, upload-time = "2025-08-16T12:11:00.119Z" }
524
+ wheels = [
525
+ { url = "https://files.pythonhosted.org/packages/23/28/1e3e5cd1d677cca68b26166f704f72e35b1e8b6d5076d8ebeebc4e40a649/mss-10.1.0-py3-none-any.whl", hash = "sha256:9179c110cadfef5dc6dc4a041a0cd161c74c379218648e6640b48c6b5cfe8918", size = 24525, upload-time = "2025-08-16T12:10:59.111Z" },
526
+ ]
527
+
519
528
  [[package]]
520
529
  name = "oagi"
521
- version = "0.14.0"
530
+ version = "0.14.1"
522
531
  source = { editable = "." }
523
532
  dependencies = [
524
533
  { name = "oagi-core", extra = ["desktop", "server"] },
525
534
  ]
526
535
 
527
536
  [package.metadata]
528
- requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.13.2" }]
537
+ requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.14.0" }]
529
538
 
530
539
  [[package]]
531
540
  name = "oagi-core"
532
- version = "0.13.2"
541
+ version = "0.14.0"
533
542
  source = { registry = "https://pypi.org/simple" }
534
543
  dependencies = [
535
544
  { name = "httpx" },
@@ -537,13 +546,14 @@ dependencies = [
537
546
  { name = "pydantic" },
538
547
  { name = "rich" },
539
548
  ]
540
- sdist = { url = "https://files.pythonhosted.org/packages/32/64/cf3f690deafbbacd17333e307f4fa6fc9daa68c69de0e426db3684c9e25b/oagi_core-0.13.2.tar.gz", hash = "sha256:f5b4957bd383ed312753b36476680e99adc42a0ff9d912054cf54021d8b132fe", size = 304580, upload-time = "2026-01-16T02:17:23.505Z" }
549
+ sdist = { url = "https://files.pythonhosted.org/packages/4d/2f/74a0a8df68ad16e66f5d84df40c439d4de059b9d2cce8b95972f7e9ff7a6/oagi_core-0.14.0.tar.gz", hash = "sha256:d72f0e81b6427ec08642678df297ff1b73b40c856d4c78df33d7e541af3bd6fd", size = 309074, upload-time = "2026-01-20T15:24:11.961Z" }
541
550
  wheels = [
542
- { url = "https://files.pythonhosted.org/packages/5b/12/8d2d0240176cfb275282c735fa57ea7620ba3f8a40ba73a2b151c1c6c3b7/oagi_core-0.13.2-py3-none-any.whl", hash = "sha256:4251a9d4f056b98d653a8e2fce3de8d19f5836130275161ec8b4733646a8933d", size = 110155, upload-time = "2026-01-16T02:17:22.055Z" },
551
+ { url = "https://files.pythonhosted.org/packages/22/c7/8061f05bf2f5225a0424ec890f50b8b38dc1e44489232a82a2405ea4a1c5/oagi_core-0.14.0-py3-none-any.whl", hash = "sha256:011a33b641dd5a881e9322bbb82e3394921574b8ce840e99b21f2de02f2d71c5", size = 114399, upload-time = "2026-01-20T15:24:10.801Z" },
543
552
  ]
544
553
 
545
554
  [package.optional-dependencies]
546
555
  desktop = [
556
+ { name = "mss", marker = "sys_platform == 'win32'" },
547
557
  { name = "pillow" },
548
558
  { name = "pyautogui" },
549
559
  { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" },
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oagi-core"
7
- version = "0.14.0"
7
+ version = "0.14.1"
8
8
  description = "Official API of OpenAGI Foundation"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -6,7 +6,6 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- import asyncio
10
9
  import logging
11
10
 
12
11
  from .. import AsyncActor
@@ -16,7 +15,7 @@ from ..constants import (
16
15
  DEFAULT_TEMPERATURE,
17
16
  MODEL_ACTOR,
18
17
  )
19
- from ..handler.utils import reset_handler
18
+ from ..handler.utils import configure_handler_delay, reset_handler
20
19
  from ..types import (
21
20
  ActionEvent,
22
21
  AsyncActionHandler,
@@ -72,6 +71,9 @@ class AsyncDefaultAgent:
72
71
  # Reset handler state at automation start
73
72
  reset_handler(action_handler)
74
73
 
74
+ # Configure handler's post_batch_delay from agent's step_delay
75
+ configure_handler_delay(action_handler, self.step_delay)
76
+
75
77
  for i in range(self.max_steps):
76
78
  step_num = i + 1
77
79
  logger.debug(f"Executing step {step_num}/{self.max_steps}")
@@ -127,10 +129,6 @@ class AsyncDefaultAgent:
127
129
  )
128
130
  )
129
131
 
130
- # Wait after actions before next screenshot
131
- if self.step_delay > 0:
132
- await asyncio.sleep(self.step_delay)
133
-
134
132
  # Check if task is complete
135
133
  if step.stop:
136
134
  logger.info(f"Task completed successfully after {step_num} steps")
@@ -6,7 +6,6 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- import asyncio
10
9
  import logging
11
10
  from datetime import datetime
12
11
  from typing import Any
@@ -19,7 +18,7 @@ from oagi.constants import (
19
18
  DEFAULT_TEMPERATURE,
20
19
  MODEL_ACTOR,
21
20
  )
22
- from oagi.handler.utils import reset_handler
21
+ from oagi.handler.utils import configure_handler_delay, reset_handler
23
22
  from oagi.types import (
24
23
  URL,
25
24
  ActionEvent,
@@ -126,6 +125,9 @@ class TaskeeAgent(AsyncAgent):
126
125
  # Reset handler state at todo execution start
127
126
  reset_handler(action_handler)
128
127
 
128
+ # Configure handler's post_batch_delay from agent's step_delay
129
+ configure_handler_delay(action_handler, self.step_delay)
130
+
129
131
  self.current_todo = instruction
130
132
  self.actions = []
131
133
  self.total_actions = 0
@@ -355,10 +357,6 @@ class TaskeeAgent(AsyncAgent):
355
357
  self.total_actions += len(step.actions)
356
358
  self.since_reflection += len(step.actions)
357
359
 
358
- # Wait after actions before next screenshot
359
- if self.step_delay > 0:
360
- await asyncio.sleep(self.step_delay)
361
-
362
360
  steps_taken += 1
363
361
 
364
362
  # Check if task is complete
@@ -29,7 +29,8 @@ class AsyncPyautoguiActionHandler:
29
29
  config: PyautoguiConfig instance for customizing behavior
30
30
  """
31
31
  self.sync_handler = PyautoguiActionHandler(config=config)
32
- self.config = config or PyautoguiConfig()
32
+ # Share the same config object so configure_handler_delay() works
33
+ self.config = self.sync_handler.config
33
34
 
34
35
  def set_target_screen(self, screen: Screen) -> None:
35
36
  """Set the target screen for the action handler.
@@ -13,6 +13,7 @@ from pydantic import BaseModel, Field
13
13
 
14
14
  from oagi.handler.screen_manager import Screen
15
15
 
16
+ from ..constants import DEFAULT_STEP_DELAY
16
17
  from ..exceptions import check_optional_dependency
17
18
  from ..types import Action, ActionType, parse_coords, parse_drag_coords, parse_scroll
18
19
  from .capslock_manager import CapsLockManager
@@ -57,6 +58,12 @@ class PyautoguiConfig(BaseModel):
57
58
  default=0.1,
58
59
  description="Delay in seconds after moving to position before clicking",
59
60
  )
61
+ post_batch_delay: float = Field(
62
+ default=DEFAULT_STEP_DELAY,
63
+ ge=0,
64
+ description="Delay after executing all actions in a batch (seconds). "
65
+ "Allows UI to settle before next screenshot.",
66
+ )
60
67
 
61
68
 
62
69
  class PyautoguiActionHandler:
@@ -292,3 +299,7 @@ class PyautoguiActionHandler:
292
299
  except Exception as e:
293
300
  print(f"Error executing action {action.type}: {e}")
294
301
  raise
302
+
303
+ # Wait after batch for UI to settle before next screenshot
304
+ if self.config.post_batch_delay > 0:
305
+ time.sleep(self.config.post_batch_delay)
@@ -19,3 +19,17 @@ def reset_handler(handler) -> None:
19
19
  """
20
20
  if hasattr(handler, "reset"):
21
21
  handler.reset()
22
+
23
+
24
+ def configure_handler_delay(handler, step_delay: float) -> None:
25
+ """Configure handler's post_batch_delay from agent's step_delay.
26
+
27
+ Uses duck-typing to check if the handler has a config with post_batch_delay.
28
+ This allows agents to control the delay after action execution.
29
+
30
+ Args:
31
+ handler: The action handler to configure
32
+ step_delay: The delay in seconds to set
33
+ """
34
+ if hasattr(handler, "config") and hasattr(handler.config, "post_batch_delay"):
35
+ handler.config.post_batch_delay = step_delay
@@ -12,6 +12,7 @@ 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
17
18
  from .wayland_support import Ydotool, get_screen_size
@@ -38,6 +39,12 @@ class YdotoolConfig(BaseModel):
38
39
  default="",
39
40
  description="Custom socket address for ydotool (e.g., '/tmp/ydotool.sock')",
40
41
  )
42
+ post_batch_delay: float = Field(
43
+ default=DEFAULT_STEP_DELAY,
44
+ ge=0,
45
+ description="Delay after executing all actions in a batch (seconds). "
46
+ "Allows UI to settle before next screenshot.",
47
+ )
41
48
 
42
49
 
43
50
  class YdotoolActionHandler(Ydotool):
@@ -241,3 +248,7 @@ class YdotoolActionHandler(Ydotool):
241
248
  except Exception as e:
242
249
  print(f"Error executing action {action.type}: {e}")
243
250
  raise
251
+
252
+ # Wait after batch for UI to settle before next screenshot
253
+ if self.config.post_batch_delay > 0:
254
+ time.sleep(self.config.post_batch_delay)
@@ -17,7 +17,10 @@ if sys.platform != "darwin":
17
17
  )
18
18
 
19
19
  from oagi.handler import _macos # noqa: E402
20
- from oagi.handler.pyautogui_action_handler import PyautoguiActionHandler
20
+ from oagi.handler.pyautogui_action_handler import (
21
+ PyautoguiActionHandler,
22
+ PyautoguiConfig,
23
+ )
21
24
  from oagi.types import Action, ActionType
22
25
 
23
26
 
@@ -77,7 +80,7 @@ def test_macos_click_implementation(mock_quartz):
77
80
 
78
81
  def test_handler_calls_macos_click_double(mock_pyautogui):
79
82
  """Test that handler calls macos_click for double click on macOS."""
80
- handler = PyautoguiActionHandler()
83
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
81
84
  action = Action(type=ActionType.LEFT_DOUBLE, argument="500, 500", count=1)
82
85
 
83
86
  with (
@@ -92,7 +95,7 @@ def test_handler_calls_macos_click_double(mock_pyautogui):
92
95
 
93
96
  def test_handler_calls_macos_click_triple(mock_pyautogui):
94
97
  """Test that handler calls macos_click for triple click on macOS."""
95
- handler = PyautoguiActionHandler()
98
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
96
99
  action = Action(type=ActionType.LEFT_TRIPLE, argument="500, 500", count=1)
97
100
 
98
101
  with (
@@ -17,6 +17,7 @@ from oagi.handler.pyautogui_action_handler import (
17
17
  PyautoguiActionHandler,
18
18
  PyautoguiConfig,
19
19
  )
20
+ from oagi.handler.utils import configure_handler_delay
20
21
  from oagi.types import Action, ActionType
21
22
 
22
23
 
@@ -29,12 +30,14 @@ def mock_pyautogui():
29
30
 
30
31
  @pytest.fixture
31
32
  def config():
32
- return PyautoguiConfig()
33
+ # Disable post_batch_delay to avoid sleeping in tests
34
+ return PyautoguiConfig(post_batch_delay=0)
33
35
 
34
36
 
35
37
  @pytest.fixture
36
38
  def handler(mock_pyautogui):
37
- return PyautoguiActionHandler()
39
+ # Disable post_batch_delay to avoid sleeping in tests
40
+ return PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
38
41
 
39
42
 
40
43
  @pytest.mark.parametrize(
@@ -109,6 +112,7 @@ def test_wait_action(handler, mock_pyautogui, config):
109
112
  with patch("time.sleep") as mock_sleep:
110
113
  action = Action(type=ActionType.WAIT, argument="", count=1)
111
114
  handler([action])
115
+ # wait_duration calls time.sleep (post_batch_delay is 0 in test fixture)
112
116
  mock_sleep.assert_called_once_with(config.wait_duration)
113
117
 
114
118
 
@@ -259,7 +263,7 @@ class TestCornerCoordinatesHandling:
259
263
  def test_corner_coordinate_adjustment(
260
264
  self, mock_pyautogui, input_coords, expected_coords
261
265
  ):
262
- handler = PyautoguiActionHandler()
266
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
263
267
  action = Action(type=ActionType.CLICK, argument=input_coords, count=1)
264
268
  handler([action])
265
269
  # Click actions now use moveTo first, then click without coordinates
@@ -268,7 +272,7 @@ class TestCornerCoordinatesHandling:
268
272
 
269
273
  def test_drag_with_corner_coordinates(self, mock_pyautogui, config):
270
274
  """Test drag operations with corner coordinates."""
271
- handler = PyautoguiActionHandler()
275
+ handler = PyautoguiActionHandler(config=config)
272
276
  # Drag from top-left corner to bottom-right corner
273
277
  action = Action(type=ActionType.DRAG, argument="0, 0, 1000, 1000", count=1)
274
278
  handler([action])
@@ -281,7 +285,7 @@ class TestCornerCoordinatesHandling:
281
285
 
282
286
  def test_scroll_with_corner_coordinates(self, mock_pyautogui, config):
283
287
  """Test scroll operations at corner coordinates."""
284
- handler = PyautoguiActionHandler()
288
+ handler = PyautoguiActionHandler(config=config)
285
289
  action = Action(type=ActionType.SCROLL, argument="0, 0, up", count=1)
286
290
  handler([action])
287
291
 
@@ -291,7 +295,7 @@ class TestCornerCoordinatesHandling:
291
295
 
292
296
  def test_multiple_clicks_at_corners(self, mock_pyautogui):
293
297
  """Test multiple clicks at corner positions."""
294
- handler = PyautoguiActionHandler()
298
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
295
299
  actions = [
296
300
  Action(type=ActionType.LEFT_DOUBLE, argument="0, 0", count=1),
297
301
  Action(type=ActionType.LEFT_TRIPLE, argument="1000, 0", count=1),
@@ -316,7 +320,7 @@ class TestCornerCoordinatesHandling:
316
320
 
317
321
  class TestCapsLockIntegration:
318
322
  def test_caps_lock_key_normalization(self, mock_pyautogui):
319
- handler = PyautoguiActionHandler()
323
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
320
324
 
321
325
  # Test different caps lock variations
322
326
  for variant in ["caps", "caps_lock", "capslock"]:
@@ -324,7 +328,7 @@ class TestCapsLockIntegration:
324
328
  assert keys == ["capslock"]
325
329
 
326
330
  def test_caps_lock_session_mode(self, mock_pyautogui):
327
- config = PyautoguiConfig(capslock_mode="session")
331
+ config = PyautoguiConfig(capslock_mode="session", post_batch_delay=0)
328
332
  handler = PyautoguiActionHandler(config=config)
329
333
 
330
334
  # Mock platform as Linux to use pyautogui.typewrite fallback
@@ -347,7 +351,7 @@ class TestCapsLockIntegration:
347
351
  mock_pyautogui.typewrite.assert_called_with("TEST")
348
352
 
349
353
  def test_caps_lock_system_mode(self, mock_pyautogui):
350
- config = PyautoguiConfig(capslock_mode="system")
354
+ config = PyautoguiConfig(capslock_mode="system", post_batch_delay=0)
351
355
  handler = PyautoguiActionHandler(config=config)
352
356
 
353
357
  # Toggle caps lock in system mode
@@ -366,7 +370,7 @@ class TestCapsLockIntegration:
366
370
 
367
371
  def test_regular_hotkey_not_affected(self, mock_pyautogui):
368
372
  # Disable macos_ctrl_to_cmd to test basic hotkey functionality
369
- config = PyautoguiConfig(macos_ctrl_to_cmd=False)
373
+ config = PyautoguiConfig(macos_ctrl_to_cmd=False, post_batch_delay=0)
370
374
  handler = PyautoguiActionHandler(config=config)
371
375
 
372
376
  # Regular hotkeys should work normally
@@ -378,14 +382,14 @@ class TestCapsLockIntegration:
378
382
  class TestMacosCtrlToCmd:
379
383
  @pytest.mark.skipif(sys.platform != "darwin", reason="macOS-specific test")
380
384
  def test_ctrl_remapped_to_command_on_macos_by_default(self, mock_pyautogui):
381
- handler = PyautoguiActionHandler()
385
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
382
386
  action = Action(type=ActionType.HOTKEY, argument="ctrl+c", count=1)
383
387
  handler([action])
384
388
  mock_pyautogui.hotkey.assert_called_once_with("command", "c", interval=0.1)
385
389
 
386
390
  @pytest.mark.skipif(sys.platform != "darwin", reason="macOS-specific test")
387
391
  def test_ctrl_not_remapped_when_disabled(self, mock_pyautogui):
388
- config = PyautoguiConfig(macos_ctrl_to_cmd=False)
392
+ config = PyautoguiConfig(macos_ctrl_to_cmd=False, post_batch_delay=0)
389
393
  handler = PyautoguiActionHandler(config=config)
390
394
  action = Action(type=ActionType.HOTKEY, argument="ctrl+c", count=1)
391
395
  handler([action])
@@ -393,7 +397,7 @@ class TestMacosCtrlToCmd:
393
397
 
394
398
  @pytest.mark.skipif(sys.platform != "darwin", reason="macOS-specific test")
395
399
  def test_multiple_keys_with_ctrl_remapped(self, mock_pyautogui):
396
- handler = PyautoguiActionHandler()
400
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
397
401
  action = Action(type=ActionType.HOTKEY, argument="ctrl+shift+a", count=1)
398
402
  handler([action])
399
403
  mock_pyautogui.hotkey.assert_called_once_with(
@@ -402,20 +406,20 @@ class TestMacosCtrlToCmd:
402
406
 
403
407
  @pytest.mark.skipif(sys.platform != "darwin", reason="macOS-specific test")
404
408
  def test_cmd_not_affected_on_macos(self, mock_pyautogui):
405
- handler = PyautoguiActionHandler()
409
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
406
410
  action = Action(type=ActionType.HOTKEY, argument="cmd+v", count=1)
407
411
  handler([action])
408
412
  mock_pyautogui.hotkey.assert_called_once_with("cmd", "v", interval=0.1)
409
413
 
410
414
  def test_ctrl_not_remapped_on_non_macos(self, mock_pyautogui):
411
415
  with patch.object(sys, "platform", "linux"):
412
- handler = PyautoguiActionHandler()
416
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
413
417
  action = Action(type=ActionType.HOTKEY, argument="ctrl+c", count=1)
414
418
  handler([action])
415
419
  mock_pyautogui.hotkey.assert_called_once_with("ctrl", "c", interval=0.1)
416
420
 
417
421
  def test_other_keys_not_affected(self, mock_pyautogui):
418
- handler = PyautoguiActionHandler()
422
+ handler = PyautoguiActionHandler(config=PyautoguiConfig(post_batch_delay=0))
419
423
  action = Action(type=ActionType.HOTKEY, argument="shift+tab", count=1)
420
424
  handler([action])
421
425
  mock_pyautogui.hotkey.assert_called_once_with("shift", "tab", interval=0.1)
@@ -423,7 +427,7 @@ class TestMacosCtrlToCmd:
423
427
 
424
428
  class TestHandlerReset:
425
429
  def test_handler_reset_resets_capslock_state(self, mock_pyautogui):
426
- config = PyautoguiConfig(capslock_mode="session")
430
+ config = PyautoguiConfig(capslock_mode="session", post_batch_delay=0)
427
431
  handler = PyautoguiActionHandler(config=config)
428
432
 
429
433
  # Enable caps lock via hotkey
@@ -436,7 +440,7 @@ class TestHandlerReset:
436
440
  assert handler.caps_manager.caps_enabled is False
437
441
 
438
442
  def test_finish_action_resets_handler(self, mock_pyautogui):
439
- config = PyautoguiConfig(capslock_mode="session")
443
+ config = PyautoguiConfig(capslock_mode="session", post_batch_delay=0)
440
444
  handler = PyautoguiActionHandler(config=config)
441
445
 
442
446
  # Enable caps lock
@@ -452,7 +456,7 @@ class TestHandlerReset:
452
456
 
453
457
  class TestAsyncHandlerReset:
454
458
  def test_async_handler_reset_delegates_to_sync_handler(self, mock_pyautogui):
455
- config = PyautoguiConfig(capslock_mode="session")
459
+ config = PyautoguiConfig(capslock_mode="session", post_batch_delay=0)
456
460
  handler = AsyncPyautoguiActionHandler(config=config)
457
461
 
458
462
  # Enable caps lock on the underlying sync handler
@@ -462,3 +466,27 @@ class TestAsyncHandlerReset:
462
466
  # Reset via async handler
463
467
  handler.reset()
464
468
  assert handler.sync_handler.caps_manager.caps_enabled is False
469
+
470
+
471
+ class TestConfigureHandlerDelay:
472
+ def test_configure_handler_delay(self, mock_pyautogui):
473
+ handler = PyautoguiActionHandler()
474
+ original_delay = handler.config.post_batch_delay
475
+
476
+ configure_handler_delay(handler, 3.0)
477
+ assert handler.config.post_batch_delay == 3.0
478
+ assert handler.config.post_batch_delay != original_delay
479
+
480
+ def test_configure_handler_delay_with_zero(self, mock_pyautogui):
481
+ handler = PyautoguiActionHandler()
482
+ configure_handler_delay(handler, 0)
483
+ assert handler.config.post_batch_delay == 0
484
+
485
+ def test_configure_handler_delay_ignores_incompatible_handler(self):
486
+ # A handler without config attribute
487
+ class DummyHandler:
488
+ pass
489
+
490
+ handler = DummyHandler()
491
+ # Should not raise
492
+ configure_handler_delay(handler, 1.0)
@@ -544,7 +544,7 @@ wheels = [
544
544
 
545
545
  [[package]]
546
546
  name = "oagi-core"
547
- version = "0.14.0"
547
+ version = "0.14.1"
548
548
  source = { editable = "." }
549
549
  dependencies = [
550
550
  { name = "httpx" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes