oagi-core 0.14.0__tar.gz → 0.14.2__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 (136) hide show
  1. {oagi_core-0.14.0 → oagi_core-0.14.2}/PKG-INFO +14 -10
  2. {oagi_core-0.14.0 → oagi_core-0.14.2}/README.md +13 -9
  3. {oagi_core-0.14.0 → oagi_core-0.14.2}/metapackage/pyproject.toml +2 -2
  4. {oagi_core-0.14.0 → oagi_core-0.14.2}/metapackage/uv.lock +15 -5
  5. {oagi_core-0.14.0 → oagi_core-0.14.2}/pyproject.toml +1 -1
  6. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/__init__.py +10 -0
  7. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/default.py +4 -6
  8. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/taskee_agent.py +4 -6
  9. oagi_core-0.14.2/src/oagi/converters/__init__.py +56 -0
  10. oagi_core-0.14.2/src/oagi/converters/base.py +292 -0
  11. oagi_core-0.14.2/src/oagi/converters/oagi.py +194 -0
  12. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/async_pyautogui_action_handler.py +2 -1
  13. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/pyautogui_action_handler.py +31 -39
  14. oagi_core-0.14.2/src/oagi/handler/utils.py +622 -0
  15. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/ydotool_action_handler.py +31 -41
  16. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_mac_double_click.py +6 -3
  17. oagi_core-0.14.2/tests/test_oagi_action_converter.py +171 -0
  18. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_pyautogui_action_handler.py +55 -27
  19. {oagi_core-0.14.0 → oagi_core-0.14.2}/uv.lock +1 -1
  20. oagi_core-0.14.0/src/oagi/handler/utils.py +0 -21
  21. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  22. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  24. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/ISSUE_TEMPLATE/question.yml +0 -0
  25. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/workflows/ci.yml +0 -0
  26. {oagi_core-0.14.0 → oagi_core-0.14.2}/.github/workflows/release.yml +0 -0
  27. {oagi_core-0.14.0 → oagi_core-0.14.2}/.gitignore +0 -0
  28. {oagi_core-0.14.0 → oagi_core-0.14.2}/.python-version +0 -0
  29. {oagi_core-0.14.0 → oagi_core-0.14.2}/CONTRIBUTING.md +0 -0
  30. {oagi_core-0.14.0 → oagi_core-0.14.2}/LICENSE +0 -0
  31. {oagi_core-0.14.0 → oagi_core-0.14.2}/Makefile +0 -0
  32. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/async_google_weather.py +0 -0
  33. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/execute_task_auto.py +0 -0
  34. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/execute_task_manual.py +0 -0
  35. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/google_weather.py +0 -0
  36. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/multi_screen_execution.py +0 -0
  37. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/openai_agent_loop_example.py +0 -0
  38. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/screenshot_with_config.py +0 -0
  39. {oagi_core-0.14.0 → oagi_core-0.14.2}/examples/tasker_agent_example.py +0 -0
  40. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/__init__.py +0 -0
  41. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/async_.py +0 -0
  42. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/async_short.py +0 -0
  43. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/base.py +0 -0
  44. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/short.py +0 -0
  45. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/actor/sync.py +0 -0
  46. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/__init__.py +0 -0
  47. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/factories.py +0 -0
  48. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/__init__.py +0 -0
  49. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/agent_observer.py +0 -0
  50. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/events.py +0 -0
  51. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/exporters.py +0 -0
  52. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/protocol.py +0 -0
  53. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/observer/report_template.html +0 -0
  54. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/protocol.py +0 -0
  55. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/registry.py +0 -0
  56. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/__init__.py +0 -0
  57. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/memory.py +0 -0
  58. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/models.py +0 -0
  59. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/planner.py +0 -0
  60. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/agent/tasker/tasker_agent.py +0 -0
  61. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/__init__.py +0 -0
  62. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/agent.py +0 -0
  63. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/display.py +0 -0
  64. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/main.py +0 -0
  65. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/server.py +0 -0
  66. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/tracking.py +0 -0
  67. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/cli/utils.py +0 -0
  68. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/client/__init__.py +0 -0
  69. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/client/async_.py +0 -0
  70. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/client/base.py +0 -0
  71. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/client/sync.py +0 -0
  72. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/constants.py +0 -0
  73. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/exceptions.py +0 -0
  74. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/__init__.py +0 -0
  75. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/_macos.py +0 -0
  76. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/_windows.py +0 -0
  77. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/_ydotool.py +0 -0
  78. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/async_screenshot_maker.py +0 -0
  79. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/async_ydotool_action_handler.py +0 -0
  80. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/capslock_manager.py +0 -0
  81. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/pil_image.py +0 -0
  82. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/screen_manager.py +0 -0
  83. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/screenshot_maker.py +0 -0
  84. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/handler/wayland_support.py +0 -0
  85. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/logging.py +0 -0
  86. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/platform_info.py +0 -0
  87. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/__init__.py +0 -0
  88. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/agent_wrappers.py +0 -0
  89. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/config.py +0 -0
  90. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/main.py +0 -0
  91. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/models.py +0 -0
  92. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/session_store.py +0 -0
  93. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/server/socketio_server.py +0 -0
  94. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/task/__init__.py +0 -0
  95. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/__init__.py +0 -0
  96. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/action_handler.py +0 -0
  97. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/async_action_handler.py +0 -0
  98. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/async_image_provider.py +0 -0
  99. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/image.py +0 -0
  100. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/image_provider.py +0 -0
  101. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/models/__init__.py +0 -0
  102. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/models/action.py +0 -0
  103. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/models/client.py +0 -0
  104. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/models/image_config.py +0 -0
  105. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/models/step.py +0 -0
  106. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/step_observer.py +0 -0
  107. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/types/url.py +0 -0
  108. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/utils/__init__.py +0 -0
  109. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/utils/output_parser.py +0 -0
  110. {oagi_core-0.14.0 → oagi_core-0.14.2}/src/oagi/utils/prompt_builder.py +0 -0
  111. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/__init__.py +0 -0
  112. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/conftest.py +0 -0
  113. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_action_parsing.py +0 -0
  114. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_actor.py +0 -0
  115. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_agent/test_agent_wrappers.py +0 -0
  116. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_agent/test_default_agent.py +0 -0
  117. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_agent_registry.py +0 -0
  118. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_async_actor.py +0 -0
  119. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_async_client.py +0 -0
  120. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_async_handlers.py +0 -0
  121. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_cli.py +0 -0
  122. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_logging.py +0 -0
  123. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_observer.py +0 -0
  124. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_pil_image.py +0 -0
  125. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_planner.py +0 -0
  126. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_planner_memory.py +0 -0
  127. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_screenshot_maker.py +0 -0
  128. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_server/__init__.py +0 -0
  129. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_server/test_config.py +0 -0
  130. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_server/test_session_store.py +0 -0
  131. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_server/test_socketio_integration.py +0 -0
  132. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_sync_client.py +0 -0
  133. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_taskee_agent.py +0 -0
  134. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/test_tasker_agent.py +0 -0
  135. {oagi_core-0.14.0 → oagi_core-0.14.2}/tests/utils/__init__.py +0 -0
  136. {oagi_core-0.14.0 → oagi_core-0.14.2}/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.2
4
4
  Summary: Official API of OpenAGI Foundation
5
5
  Project-URL: Homepage, https://github.com/agiopen-org/oagi
6
6
  Author-email: OpenAGI Foundation <contact@agiopen.org>
@@ -154,12 +154,15 @@ from oagi import AsyncPyautoguiActionHandler, PyautoguiConfig
154
154
 
155
155
  # Customize action behavior
156
156
  config = PyautoguiConfig(
157
- drag_duration=1.0, # Slower drags for precision (default: 0.5)
158
- scroll_amount=50, # Larger scroll steps (default: 30)
159
- wait_duration=2.0, # Longer waits (default: 1.0)
160
- action_pause=0.2, # More pause between actions (default: 0.1)
161
- hotkey_interval=0.1, # Interval between keys in hotkey combinations (default: 0.1)
162
- capslock_mode="session" # Caps lock mode: 'session' or 'system' (default: 'session')
157
+ drag_duration=1.0, # Slower drags for precision (default: 0.5)
158
+ scroll_amount=50, # Larger scroll steps (default: 2 on macOS, 100 on others)
159
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
160
+ action_pause=0.2, # Pause between PyAutoGUI calls (default: 0.1)
161
+ hotkey_interval=0.1, # Interval between keys in hotkey combos (default: 0.1)
162
+ capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
163
+ macos_ctrl_to_cmd=True, # Replace ctrl with cmd on macOS (default: True)
164
+ click_pre_delay=0.1, # Delay after move before click (default: 0.1)
165
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
163
166
  )
164
167
 
165
168
  action_handler = AsyncPyautoguiActionHandler(config=config)
@@ -279,10 +282,11 @@ from oagi import AsyncYdotoolActionHandler, YdotoolConfig
279
282
  # Customize action behavior
280
283
  config = YdotoolConfig(
281
284
  scroll_amount=50, # Larger scroll steps (default: 20)
282
- wait_duration=2.0, # Longer waits (default: 1.0)
283
- action_pause=1.0, # More pause between actions (default: 0.5)
285
+ wait_duration=2.0, # Longer waits for WAIT action (default: 1.0)
286
+ action_pause=1.0, # Pause between Ydotool calls (default: 0.5)
284
287
  capslock_mode="session", # Caps lock mode: 'session' or 'system' (default: 'session')
285
- socket_address="/tmp/ydotool.sock" # Customized Socket address for ydotool (ydotool uses 'YDOTOOL_SOCKET' environment variable by default)
288
+ socket_address="/tmp/ydotool.sock", # Custom socket address (default: YDOTOOL_SOCKET env var)
289
+ post_batch_delay=1.0, # Delay after actions before next screenshot (default: 1.0)
286
290
  )
287
291
 
288
292
  action_handler = AsyncYdotoolActionHandler(config=config)
@@ -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.2"
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.2",
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.2"
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.1" }]
529
538
 
530
539
  [[package]]
531
540
  name = "oagi-core"
532
- version = "0.13.2"
541
+ version = "0.14.1"
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/94/20/3dfff9883e8786fc0b79ea915ba83cfbce3addd3149568601b80c3bc83a3/oagi_core-0.14.1.tar.gz", hash = "sha256:407faa59b3ced203901a1b35a5b3bc25407e8b61f82ab9b202f01412c73175bf", size = 310008, upload-time = "2026-01-23T08:09:08.54Z" }
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/62/d1/4485bbddbdf1868aa46deaa98d49ad4624e243c9b32321c81374402bcde8/oagi_core-0.14.1-py3-none-any.whl", hash = "sha256:36b0e10a79c0508eedd28f8a5d89230b7236452ed64bed7150b22f99a50f1a18", size = 114938, upload-time = "2026-01-23T08:09:07.4Z" },
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.2"
8
8
  description = "Official API of OpenAGI Foundation"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -38,6 +38,10 @@ from oagi.types.models import (
38
38
  # Format: name -> (module_path, package_to_check, extra_name)
39
39
  # package_to_check is None if no optional dependency is required
40
40
  _LAZY_IMPORTS_DATA: dict[str, tuple[str, str | None, str | None]] = {
41
+ # Action converters (no optional dependencies)
42
+ "OagiActionConverter": ("oagi.converters.oagi", None, None),
43
+ "ConverterConfig": ("oagi.converters.base", None, None),
44
+ "BaseActionConverter": ("oagi.converters.base", None, None),
41
45
  # Desktop handlers (require pyautogui/PIL)
42
46
  "AsyncPyautoguiActionHandler": (
43
47
  "oagi.handler.async_pyautogui_action_handler",
@@ -88,6 +92,8 @@ if TYPE_CHECKING:
88
92
  from oagi.agent.default import AsyncDefaultAgent
89
93
  from oagi.agent.observer.agent_observer import AsyncAgentObserver
90
94
  from oagi.agent.tasker import TaskerAgent
95
+ from oagi.converters.base import BaseActionConverter, ConverterConfig
96
+ from oagi.converters.oagi import OagiActionConverter
91
97
  from oagi.handler.async_pyautogui_action_handler import AsyncPyautoguiActionHandler
92
98
  from oagi.handler.async_screenshot_maker import AsyncScreenshotMaker
93
99
  from oagi.handler.async_ydotool_action_handler import AsyncYdotoolActionHandler
@@ -174,4 +180,8 @@ __all__ = [
174
180
  "YdotoolConfig",
175
181
  # Lazy imports - Screen manager
176
182
  "ScreenManager",
183
+ # Lazy imports - Action converters
184
+ "OagiActionConverter",
185
+ "ConverterConfig",
186
+ "BaseActionConverter",
177
187
  ]
@@ -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
@@ -0,0 +1,56 @@
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
+ """Action converters for VLM support.
9
+
10
+ This module provides the base class and OAGI implementation for action converters.
11
+ Third parties can inherit from BaseActionConverter to create custom converters.
12
+
13
+ Example usage:
14
+ from oagi.converters import OagiActionConverter, ConverterConfig
15
+
16
+ # Configure for 1920x1080 sandbox
17
+ config = ConverterConfig(sandbox_width=1920, sandbox_height=1080)
18
+ converter = OagiActionConverter(config=config)
19
+
20
+ # Convert OAGI actions to pyautogui strings
21
+ result = converter(actions) # list[str]
22
+
23
+ # Convert to runtime API steps
24
+ for cmd in result:
25
+ step = converter.action_string_to_step(cmd)
26
+ # Execute step via runtime API...
27
+
28
+ Creating custom converters:
29
+ from oagi.converters import BaseActionConverter, ConverterConfig
30
+
31
+ class MyActionConverter(BaseActionConverter[MyAction]):
32
+ @property
33
+ def coord_width(self) -> int:
34
+ return 1000 # Your model's coordinate width
35
+
36
+ @property
37
+ def coord_height(self) -> int:
38
+ return 1000 # Your model's coordinate height
39
+
40
+ def _convert_single_action(self, action: MyAction) -> list[str]:
41
+ # Convert action to pyautogui command strings
42
+ ...
43
+
44
+ def serialize_actions(self, actions: list[MyAction]) -> list[dict]:
45
+ # Serialize actions for trajectory logging
46
+ ...
47
+ """
48
+
49
+ from .base import BaseActionConverter, ConverterConfig
50
+ from .oagi import OagiActionConverter
51
+
52
+ __all__ = [
53
+ "BaseActionConverter",
54
+ "ConverterConfig",
55
+ "OagiActionConverter",
56
+ ]
@@ -0,0 +1,292 @@
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
+ """Base class for action converters.
9
+
10
+ This module provides the abstract base class for converting model-specific
11
+ actions to pyautogui command strings for remote execution.
12
+ """
13
+
14
+ import re
15
+ from abc import ABC, abstractmethod
16
+ from dataclasses import dataclass
17
+ from typing import Any, Generic, TypeVar
18
+
19
+ from ..handler.capslock_manager import CapsLockManager
20
+ from ..handler.utils import (
21
+ CoordinateScaler,
22
+ normalize_key,
23
+ parse_hotkey,
24
+ validate_keys,
25
+ )
26
+
27
+ T = TypeVar("T")
28
+
29
+
30
+ @dataclass
31
+ class ConverterConfig:
32
+ """Configuration for action converters.
33
+
34
+ Matches the configuration options in PyautoguiConfig for consistency.
35
+ """
36
+
37
+ sandbox_width: int = 1920
38
+ sandbox_height: int = 1080
39
+ drag_duration: float = 0.5
40
+ scroll_amount: int = 2
41
+ wait_duration: float = 1.0
42
+ hotkey_interval: float = 0.1
43
+ capslock_mode: str = "session"
44
+ strict_coordinate_validation: bool = False
45
+ """If True, raise ValueError when coordinates are outside valid range.
46
+ If False (default), clamp coordinates to valid range (original behavior)."""
47
+
48
+
49
+ class BaseActionConverter(ABC, Generic[T]):
50
+ """Abstract base class for action converters.
51
+
52
+ Subclasses must implement:
53
+ - coord_width/coord_height properties for input coordinate space
54
+ - _convert_single_action() for model-specific conversion logic
55
+ - serialize_actions() for trajectory logging
56
+
57
+ Provides common functionality:
58
+ - Coordinate scaling via CoordinateScaler
59
+ - Key normalization via shared utils
60
+ - __call__ interface returning list of action strings
61
+ - action_string_to_step() for runtime API format
62
+ """
63
+
64
+ def __init__(
65
+ self,
66
+ *,
67
+ config: ConverterConfig | None = None,
68
+ logger: Any | None = None,
69
+ ):
70
+ """Initialize the converter.
71
+
72
+ Args:
73
+ config: Converter configuration. Uses defaults if not provided.
74
+ logger: Optional logger instance for debug/error logging.
75
+ """
76
+ self.config = config or ConverterConfig()
77
+ self.logger = logger
78
+
79
+ # Initialize coordinate scaler
80
+ self._coord_scaler = CoordinateScaler(
81
+ source_width=self.coord_width,
82
+ source_height=self.coord_height,
83
+ target_width=self.config.sandbox_width,
84
+ target_height=self.config.sandbox_height,
85
+ )
86
+
87
+ # Initialize caps lock manager
88
+ self.caps_manager = CapsLockManager(mode=self.config.capslock_mode)
89
+
90
+ # Track last cursor position (for actions without explicit coordinates)
91
+ self._last_x: int | None = None
92
+ self._last_y: int | None = None
93
+
94
+ @property
95
+ @abstractmethod
96
+ def coord_width(self) -> int:
97
+ """Input coordinate space width (e.g., 1024 for XGA, 1000 for OAGI)."""
98
+ ...
99
+
100
+ @property
101
+ @abstractmethod
102
+ def coord_height(self) -> int:
103
+ """Input coordinate space height (e.g., 768 for XGA, 1000 for OAGI)."""
104
+ ...
105
+
106
+ @property
107
+ def scale_x(self) -> float:
108
+ """X scaling factor from input to sandbox coordinates."""
109
+ return self._coord_scaler.scale_x
110
+
111
+ @property
112
+ def scale_y(self) -> float:
113
+ """Y scaling factor from input to sandbox coordinates."""
114
+ return self._coord_scaler.scale_y
115
+
116
+ def scale_coordinate(self, x: int | float, y: int | float) -> tuple[int, int]:
117
+ """Scale coordinates from model space to sandbox space.
118
+
119
+ Args:
120
+ x: X coordinate in model space
121
+ y: Y coordinate in model space
122
+
123
+ Returns:
124
+ Tuple of (scaled_x, scaled_y) in sandbox space
125
+ """
126
+ return self._coord_scaler.scale(x, y)
127
+
128
+ def normalize_key(self, key: str) -> str:
129
+ """Normalize a key name to pyautogui format.
130
+
131
+ Args:
132
+ key: Key name to normalize
133
+
134
+ Returns:
135
+ Normalized key name
136
+ """
137
+ return normalize_key(key)
138
+
139
+ def parse_hotkey(self, hotkey_str: str, *, validate: bool = True) -> list[str]:
140
+ """Parse a hotkey string into a list of normalized key names.
141
+
142
+ Args:
143
+ hotkey_str: Hotkey string (e.g., "ctrl+c")
144
+ validate: If True, validate keys against PYAUTOGUI_VALID_KEYS
145
+
146
+ Returns:
147
+ List of normalized key names
148
+ """
149
+ return parse_hotkey(hotkey_str, validate=validate)
150
+
151
+ def validate_keys(self, keys: list[str]) -> None:
152
+ """Validate that all keys are recognized by pyautogui.
153
+
154
+ Args:
155
+ keys: List of key names to validate
156
+
157
+ Raises:
158
+ ValueError: If any key is invalid
159
+ """
160
+ validate_keys(keys)
161
+
162
+ def _get_last_or_center(self) -> tuple[int, int]:
163
+ """Get last cursor position or screen center as fallback.
164
+
165
+ Returns:
166
+ Tuple of (x, y) coordinates
167
+ """
168
+ if self._last_x is not None and self._last_y is not None:
169
+ return self._last_x, self._last_y
170
+ return self.config.sandbox_width // 2, self.config.sandbox_height // 2
171
+
172
+ def _log_error(self, message: str) -> None:
173
+ """Log an error message if logger is available."""
174
+ if self.logger:
175
+ self.logger.error(message)
176
+
177
+ def _log_info(self, message: str) -> None:
178
+ """Log an info message if logger is available."""
179
+ if self.logger:
180
+ self.logger.info(message)
181
+
182
+ def _log_debug(self, message: str) -> None:
183
+ """Log a debug message if logger is available."""
184
+ if self.logger:
185
+ self.logger.debug(message)
186
+
187
+ def __call__(self, actions: list[T]) -> list[str]:
188
+ """Convert actions to list of pyautogui command strings.
189
+
190
+ Args:
191
+ actions: List of model-specific action objects
192
+
193
+ Returns:
194
+ List of pyautogui command strings
195
+
196
+ Raises:
197
+ RuntimeError: If all action conversions failed
198
+ """
199
+ converted: list[str] = []
200
+ failed: list[tuple[str, str]] = []
201
+ skipped: list[str] = []
202
+
203
+ if not actions:
204
+ return converted
205
+
206
+ for action in actions:
207
+ try:
208
+ action_strings = self._convert_single_action(action)
209
+
210
+ if not action_strings:
211
+ # No-op action (e.g., screenshot, cursor_position)
212
+ action_type = getattr(action, "action_type", repr(action))
213
+ skipped.append(str(action_type))
214
+ continue
215
+
216
+ converted.extend(action_strings)
217
+
218
+ except Exception as e:
219
+ action_repr = repr(action)
220
+ self._log_error(f"Failed to convert action: {action_repr}, error: {e}")
221
+ failed.append((action_repr, str(e)))
222
+
223
+ if skipped:
224
+ self._log_debug(f"Skipped no-op actions: {skipped}")
225
+
226
+ if not converted and actions and failed:
227
+ raise RuntimeError(
228
+ f"All action conversions failed ({len(failed)}/{len(actions)}): {failed}"
229
+ )
230
+
231
+ return converted
232
+
233
+ @abstractmethod
234
+ def _convert_single_action(self, action: T) -> list[str]:
235
+ """Convert a single action to pyautogui command string(s).
236
+
237
+ Args:
238
+ action: Model-specific action object
239
+
240
+ Returns:
241
+ List of pyautogui command strings (may be empty for no-op actions)
242
+
243
+ Raises:
244
+ ValueError: If action format is invalid
245
+ """
246
+ ...
247
+
248
+ @abstractmethod
249
+ def serialize_actions(self, actions: list[T]) -> list[dict[str, Any]]:
250
+ """Serialize actions for trajectory logging.
251
+
252
+ Args:
253
+ actions: List of model-specific action objects
254
+
255
+ Returns:
256
+ List of serialized action dictionaries
257
+ """
258
+ ...
259
+
260
+ def action_string_to_step(self, action: str) -> dict[str, Any]:
261
+ """Convert an action string into a step for runtime/do API.
262
+
263
+ Args:
264
+ action: Action string (e.g., "pyautogui.click(x=100, y=200)")
265
+
266
+ Returns:
267
+ Step dict for runtime API
268
+ """
269
+ action_str = str(action).strip()
270
+
271
+ # Special markers
272
+ upper = action_str.upper()
273
+ if upper in ["DONE", "FAIL"]:
274
+ return {"type": "sleep", "parameters": {"seconds": 0}}
275
+
276
+ # WAIT(seconds)
277
+ wait_match = re.match(
278
+ r"^WAIT\((?P<sec>[0-9]*\.?[0-9]+)\)$", action_str, re.IGNORECASE
279
+ )
280
+ if wait_match:
281
+ seconds = float(wait_match.group("sec"))
282
+ return {"type": "sleep", "parameters": {"seconds": seconds}}
283
+
284
+ # pyautogui code path
285
+ if "pyautogui" in action_str.lower():
286
+ return {
287
+ "type": "pyautogui",
288
+ "parameters": {"code": action_str},
289
+ }
290
+
291
+ # Default: shell command
292
+ return {"type": "execute", "parameters": {"command": action_str, "shell": True}}