oagi-core 0.9.0__tar.gz → 0.9.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 (106) hide show
  1. {oagi_core-0.9.0 → oagi_core-0.9.1}/Makefile +2 -1
  2. {oagi_core-0.9.0 → oagi_core-0.9.1}/PKG-INFO +3 -29
  3. {oagi_core-0.9.0 → oagi_core-0.9.1}/README.md +1 -28
  4. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/execute_task_manual.py +12 -12
  5. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/screenshot_with_config.py +3 -27
  6. {oagi_core-0.9.0 → oagi_core-0.9.1}/metapackage/pyproject.toml +2 -2
  7. {oagi_core-0.9.0 → oagi_core-0.9.1}/pyproject.toml +2 -1
  8. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/__init__.py +13 -16
  9. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/default.py +23 -7
  10. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/factories.py +5 -0
  11. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/taskee_agent.py +40 -15
  12. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/tasker_agent.py +5 -1
  13. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/cli/agent.py +31 -15
  14. oagi_core-0.9.1/src/oagi/cli/display.py +56 -0
  15. oagi_core-0.9.1/src/oagi/cli/tracking.py +45 -0
  16. oagi_core-0.9.1/src/oagi/handler/__init__.py +24 -0
  17. {oagi_core-0.9.0/src/oagi → oagi_core-0.9.1/src/oagi/handler}/async_pyautogui_action_handler.py +1 -1
  18. {oagi_core-0.9.0/src/oagi → oagi_core-0.9.1/src/oagi/handler}/async_screenshot_maker.py +1 -1
  19. {oagi_core-0.9.0/src/oagi → oagi_core-0.9.1/src/oagi/handler}/pil_image.py +2 -2
  20. {oagi_core-0.9.0/src/oagi → oagi_core-0.9.1/src/oagi/handler}/pyautogui_action_handler.py +2 -2
  21. {oagi_core-0.9.0/src/oagi → oagi_core-0.9.1/src/oagi/handler}/screenshot_maker.py +2 -2
  22. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/logging.py +8 -0
  23. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/__init__.py +10 -3
  24. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/async_.py +26 -1
  25. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/async_short.py +15 -3
  26. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/base.py +2 -0
  27. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/short.py +15 -3
  28. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/task/sync.py +26 -1
  29. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/__init__.py +2 -0
  30. oagi_core-0.9.1/src/oagi/types/step_observer.py +34 -0
  31. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_agent/test_default_agent.py +19 -13
  32. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_async_handlers.py +3 -3
  33. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_async_task.py +47 -45
  34. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_cli.py +4 -2
  35. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_pil_image.py +3 -3
  36. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_pyautogui_action_handler.py +2 -2
  37. oagi_core-0.9.1/tests/test_task.py +427 -0
  38. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_taskee_agent.py +18 -16
  39. {oagi_core-0.9.0 → oagi_core-0.9.1}/uv.lock +3 -1
  40. oagi_core-0.9.0/examples/single_step.py +0 -19
  41. oagi_core-0.9.0/src/oagi/async_single_step.py +0 -85
  42. oagi_core-0.9.0/src/oagi/single_step.py +0 -87
  43. oagi_core-0.9.0/tests/test_single_step.py +0 -216
  44. oagi_core-0.9.0/tests/test_task.py +0 -423
  45. {oagi_core-0.9.0 → oagi_core-0.9.1}/.github/workflows/ci.yml +0 -0
  46. {oagi_core-0.9.0 → oagi_core-0.9.1}/.github/workflows/release.yml +0 -0
  47. {oagi_core-0.9.0 → oagi_core-0.9.1}/.gitignore +0 -0
  48. {oagi_core-0.9.0 → oagi_core-0.9.1}/.python-version +0 -0
  49. {oagi_core-0.9.0 → oagi_core-0.9.1}/CONTRIBUTING.md +0 -0
  50. {oagi_core-0.9.0 → oagi_core-0.9.1}/LICENSE +0 -0
  51. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/async_google_weather.py +0 -0
  52. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/continued_session.py +0 -0
  53. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/execute_task_auto.py +0 -0
  54. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/google_weather.py +0 -0
  55. {oagi_core-0.9.0 → oagi_core-0.9.1}/examples/hotel_booking.py +0 -0
  56. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/__init__.py +0 -0
  57. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/protocol.py +0 -0
  58. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/registry.py +0 -0
  59. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/__init__.py +0 -0
  60. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/memory.py +0 -0
  61. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/models.py +0 -0
  62. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/agent/tasker/planner.py +0 -0
  63. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/cli/__init__.py +0 -0
  64. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/cli/main.py +0 -0
  65. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/cli/server.py +0 -0
  66. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/cli/utils.py +0 -0
  67. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/client/__init__.py +0 -0
  68. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/client/async_.py +0 -0
  69. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/client/base.py +0 -0
  70. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/client/sync.py +0 -0
  71. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/exceptions.py +0 -0
  72. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/__init__.py +0 -0
  73. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/agent_wrappers.py +0 -0
  74. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/config.py +0 -0
  75. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/main.py +0 -0
  76. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/models.py +0 -0
  77. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/session_store.py +0 -0
  78. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/server/socketio_server.py +0 -0
  79. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/action_handler.py +0 -0
  80. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/async_action_handler.py +0 -0
  81. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/async_image_provider.py +0 -0
  82. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/image.py +0 -0
  83. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/image_provider.py +0 -0
  84. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/models/__init__.py +0 -0
  85. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/models/action.py +0 -0
  86. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/models/client.py +0 -0
  87. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/models/image_config.py +0 -0
  88. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/models/step.py +0 -0
  89. {oagi_core-0.9.0 → oagi_core-0.9.1}/src/oagi/types/url_image.py +0 -0
  90. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/__init__.py +0 -0
  91. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/conftest.py +0 -0
  92. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_agent/test_agent_wrappers.py +0 -0
  93. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_agent_registry.py +0 -0
  94. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_async_client.py +0 -0
  95. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_logging.py +0 -0
  96. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_planner.py +0 -0
  97. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_planner_memory.py +0 -0
  98. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_screenshot_maker.py +0 -0
  99. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_server/__init__.py +0 -0
  100. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_server/test_config.py +0 -0
  101. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_server/test_session_store.py +0 -0
  102. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_server/test_socketio_integration.py +0 -0
  103. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_short_task.py +0 -0
  104. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_sync_client.py +0 -0
  105. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_tasker_agent.py +0 -0
  106. {oagi_core-0.9.0 → oagi_core-0.9.1}/tests/test_url_image.py +0 -0
@@ -54,4 +54,5 @@ version:
54
54
  @echo "Updating version to $(VERSION) in all files..."
55
55
  @sed -i '' 's/^version = ".*"/version = "$(VERSION)"/' pyproject.toml
56
56
  @sed -i '' 's/^version = ".*"/version = "$(VERSION)"/' metapackage/pyproject.toml
57
- @sed -i '' 's/oagi-core\[desktop,server\]==.*/oagi-core[desktop,server]==$(VERSION)",/' metapackage/pyproject.toml
57
+ @sed -i '' 's/oagi-core\[desktop,server\]==.*/oagi-core[desktop,server]==$(VERSION)",/' metapackage/pyproject.toml
58
+ make build-all
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: oagi-core
3
- Version: 0.9.0
3
+ Version: 0.9.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>
@@ -28,6 +28,7 @@ License: MIT License
28
28
  Requires-Python: >=3.10
29
29
  Requires-Dist: httpx>=0.28.0
30
30
  Requires-Dist: pydantic>=2.0.0
31
+ Requires-Dist: rich>=13.0.0
31
32
  Provides-Extra: desktop
32
33
  Requires-Dist: pillow>=11.3.0; extra == 'desktop'
33
34
  Requires-Dist: pyautogui>=0.9.54; extra == 'desktop'
@@ -75,22 +76,6 @@ export OAGI_API_KEY="your-api-key"
75
76
  export OAGI_BASE_URL="https://api.oagi.com" # or your server URL
76
77
  ```
77
78
 
78
- ### Single-Step Analysis
79
-
80
- Analyze a screenshot and get recommended actions:
81
-
82
- ```python
83
- from oagi import single_step
84
-
85
- step = single_step(
86
- task_description="Click the submit button",
87
- screenshot="screenshot.png" # or bytes, or Image object
88
- )
89
-
90
- print(f"Actions: {step.actions}")
91
- print(f"Complete: {step.is_complete}")
92
- ```
93
-
94
79
  ### Automated Task Execution
95
80
 
96
81
  Run tasks automatically with screenshot capture and action execution:
@@ -142,9 +127,6 @@ config = ImageConfig(
142
127
  height=700
143
128
  )
144
129
  compressed = image.transform(config)
145
-
146
- # Use with single_step
147
- step = single_step("Click button", screenshot=compressed)
148
130
  ```
149
131
 
150
132
  ### Async Support
@@ -153,16 +135,9 @@ Use async client for non-blocking operations and better concurrency:
153
135
 
154
136
  ```python
155
137
  import asyncio
156
- from oagi import async_single_step, AsyncShortTask
138
+ from oagi import AsyncShortTask
157
139
 
158
140
  async def main():
159
- # Single-step async analysis
160
- step = await async_single_step(
161
- "Find the search bar",
162
- screenshot="screenshot.png"
163
- )
164
- print(f"Found {len(step.actions)} actions")
165
-
166
141
  # Async task automation
167
142
  task = AsyncShortTask()
168
143
  async with task:
@@ -176,7 +151,6 @@ asyncio.run(main())
176
151
 
177
152
  See the [`examples/`](examples/) directory for more usage patterns:
178
153
  - `google_weather.py` - Basic task execution with `ShortTask`
179
- - `single_step.py` - Basic single-step inference
180
154
  - `screenshot_with_config.py` - Image compression and optimization
181
155
  - `execute_task_auto.py` - Automated task execution
182
156
  - `socketio_server_basic.py` - Socket.IO server example
@@ -35,22 +35,6 @@ export OAGI_API_KEY="your-api-key"
35
35
  export OAGI_BASE_URL="https://api.oagi.com" # or your server URL
36
36
  ```
37
37
 
38
- ### Single-Step Analysis
39
-
40
- Analyze a screenshot and get recommended actions:
41
-
42
- ```python
43
- from oagi import single_step
44
-
45
- step = single_step(
46
- task_description="Click the submit button",
47
- screenshot="screenshot.png" # or bytes, or Image object
48
- )
49
-
50
- print(f"Actions: {step.actions}")
51
- print(f"Complete: {step.is_complete}")
52
- ```
53
-
54
38
  ### Automated Task Execution
55
39
 
56
40
  Run tasks automatically with screenshot capture and action execution:
@@ -102,9 +86,6 @@ config = ImageConfig(
102
86
  height=700
103
87
  )
104
88
  compressed = image.transform(config)
105
-
106
- # Use with single_step
107
- step = single_step("Click button", screenshot=compressed)
108
89
  ```
109
90
 
110
91
  ### Async Support
@@ -113,16 +94,9 @@ Use async client for non-blocking operations and better concurrency:
113
94
 
114
95
  ```python
115
96
  import asyncio
116
- from oagi import async_single_step, AsyncShortTask
97
+ from oagi import AsyncShortTask
117
98
 
118
99
  async def main():
119
- # Single-step async analysis
120
- step = await async_single_step(
121
- "Find the search bar",
122
- screenshot="screenshot.png"
123
- )
124
- print(f"Found {len(step.actions)} actions")
125
-
126
100
  # Async task automation
127
101
  task = AsyncShortTask()
128
102
  async with task:
@@ -136,7 +110,6 @@ asyncio.run(main())
136
110
 
137
111
  See the [`examples/`](examples/) directory for more usage patterns:
138
112
  - `google_weather.py` - Basic task execution with `ShortTask`
139
- - `single_step.py` - Basic single-step inference
140
113
  - `screenshot_with_config.py` - Image compression and optimization
141
114
  - `execute_task_auto.py` - Automated task execution
142
115
  - `socketio_server_basic.py` - Socket.IO server example
@@ -7,20 +7,20 @@
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
9
  from oagi import (
10
+ Actor,
11
+ AsyncActor,
10
12
  AsyncPyautoguiActionHandler,
11
13
  AsyncScreenshotMaker,
12
- AsyncTask,
13
14
  PyautoguiActionHandler,
14
15
  ScreenshotMaker,
15
- Task,
16
16
  )
17
17
 
18
18
 
19
19
  def execute_task_manual(task_desc, max_steps=5):
20
20
  # set OAGI_API_KEY and OAGI_BASE_URL
21
- # or ShortTask(api_key="your_api_key", base_url="your_base_url")
22
- task = Task()
23
- task.init_task(task_desc, max_steps=max_steps)
21
+ # or Actor(api_key="your_api_key", base_url="your_base_url")
22
+ actor = Actor()
23
+ actor.init_task(task_desc, max_steps=max_steps)
24
24
  executor = (
25
25
  PyautoguiActionHandler()
26
26
  ) # executor = lambda actions: print(actions) for debugging
@@ -36,8 +36,8 @@ def execute_task_manual(task_desc, max_steps=5):
36
36
  image = image_provider()
37
37
 
38
38
  # For additional instructions
39
- # step = task.step(image, instruction="some instruction")
40
- step = task.step(image)
39
+ # step = actor.step(image, instruction="some instruction")
40
+ step = actor.step(image)
41
41
 
42
42
  # do something with step, maybe print to debug
43
43
  print(f"Step {i}: {step.reason=}")
@@ -60,9 +60,9 @@ def execute_task_manual(task_desc, max_steps=5):
60
60
 
61
61
  async def async_execute_task_manual(task_desc, max_steps=5):
62
62
  # set OAGI_API_KEY and OAGI_BASE_URL
63
- # or ShortTask(api_key="your_api_key", base_url="your_base_url")
64
- async with AsyncTask() as task:
65
- await task.init_task(task_desc, max_steps=max_steps)
63
+ # or AsyncActor(api_key="your_api_key", base_url="your_base_url")
64
+ async with AsyncActor() as actor:
65
+ await actor.init_task(task_desc, max_steps=max_steps)
66
66
  executor = AsyncPyautoguiActionHandler()
67
67
 
68
68
  # by default, screenshot will be resized to 1260 * 700 and jpeg with quality 85
@@ -76,8 +76,8 @@ async def async_execute_task_manual(task_desc, max_steps=5):
76
76
  image = await image_provider()
77
77
 
78
78
  # For additional instructions
79
- # step = task.step(image, instruction="some instruction")
80
- step = await task.step(image)
79
+ # step = actor.step(image, instruction="some instruction")
80
+ step = await actor.step(image)
81
81
 
82
82
  # do something with step, maybe print to debug
83
83
  print(f"Step {i}: {step.reason=}")
@@ -6,7 +6,7 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- from oagi import ImageConfig, PILImage, ScreenshotMaker, single_step
9
+ from oagi import ImageConfig, PILImage, ScreenshotMaker
10
10
 
11
11
 
12
12
  def example_full_png_screenshot():
@@ -53,33 +53,9 @@ def example_load_and_compress(file_name):
53
53
  return compressed_image
54
54
 
55
55
 
56
- def example_with_single_step(file_name):
57
- """Example 3: Use compressed image with single_step."""
58
- print("\nExample 3: Use with single_step")
59
-
60
- # Load and compress image
61
- image = PILImage.from_file(file_name)
62
- print(f"Original image dimensions: {image.image.size}")
63
-
64
- config = ImageConfig(format="JPEG", quality=85, width=1260, height=700)
65
- compressed = image.transform(config)
66
- print(f"Compressed image dimensions: {compressed.image.size}")
67
-
68
- # Use with single_step
69
- step = single_step(
70
- task_description="Click the submit button",
71
- screenshot=compressed,
72
- api_key="your-api-key-here",
73
- base_url="http://127.0.0.1:8000",
74
- )
75
-
76
- print(f"Task complete: {step.is_complete}")
77
- return step
78
-
79
-
80
56
  def example_default_config():
81
- """Example 4: Default configuration (1260x700 JPEG with 85 quality)."""
82
- print("\nExample 4: Default configuration")
57
+ """Example 3: Default configuration (1260x700 JPEG with 85 quality)."""
58
+ print("\nExample 3: Default configuration")
83
59
 
84
60
  default_maker = ScreenshotMaker() # Uses default ImageConfig
85
61
  default_screenshot = default_maker()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oagi"
7
- version = "0.9.0"
7
+ version = "0.9.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.9.0",
19
+ "oagi-core[desktop,server]==0.9.1",
20
20
  ]
21
21
 
22
22
  [project.urls]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oagi-core"
7
- version = "0.9.0"
7
+ version = "0.9.1"
8
8
  description = "Official API of OpenAGI Foundation"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -17,6 +17,7 @@ requires-python = ">= 3.10"
17
17
  dependencies = [
18
18
  "httpx>=0.28.0",
19
19
  "pydantic>=2.0.0",
20
+ "rich>=13.0.0",
20
21
  ]
21
22
 
22
23
  [project.urls]
@@ -7,7 +7,6 @@
7
7
  # -----------------------------------------------------------------------------
8
8
  import importlib
9
9
 
10
- from oagi.async_single_step import async_single_step
11
10
  from oagi.client import AsyncClient, SyncClient
12
11
  from oagi.exceptions import (
13
12
  APIError,
@@ -21,8 +20,7 @@ from oagi.exceptions import (
21
20
  ServerError,
22
21
  ValidationError,
23
22
  )
24
- from oagi.single_step import single_step
25
- from oagi.task import AsyncShortTask, AsyncTask, ShortTask, Task
23
+ from oagi.task import Actor, AsyncActor, AsyncShortTask, AsyncTask, ShortTask, Task
26
24
  from oagi.types import (
27
25
  AsyncActionHandler,
28
26
  AsyncImageProvider,
@@ -33,12 +31,12 @@ from oagi.types.models import ErrorDetail, ErrorResponse, LLMResponse
33
31
  # Lazy imports for pyautogui-dependent modules
34
32
  # These will only be imported when actually accessed
35
33
  _LAZY_IMPORTS = {
36
- "AsyncPyautoguiActionHandler": "oagi.async_pyautogui_action_handler",
37
- "AsyncScreenshotMaker": "oagi.async_screenshot_maker",
38
- "PILImage": "oagi.pil_image",
39
- "PyautoguiActionHandler": "oagi.pyautogui_action_handler",
40
- "PyautoguiConfig": "oagi.pyautogui_action_handler",
41
- "ScreenshotMaker": "oagi.screenshot_maker",
34
+ "AsyncPyautoguiActionHandler": "oagi.handler.async_pyautogui_action_handler",
35
+ "AsyncScreenshotMaker": "oagi.handler.async_screenshot_maker",
36
+ "PILImage": "oagi.handler.pil_image",
37
+ "PyautoguiActionHandler": "oagi.handler.pyautogui_action_handler",
38
+ "PyautoguiConfig": "oagi.handler.pyautogui_action_handler",
39
+ "ScreenshotMaker": "oagi.handler.screenshot_maker",
42
40
  # Agent modules (to avoid circular imports)
43
41
  "TaskerAgent": "oagi.agent.tasker",
44
42
  # Server modules (optional - requires server dependencies)
@@ -59,18 +57,17 @@ def __getattr__(name: str):
59
57
 
60
58
  __all__ = [
61
59
  # Core sync classes
62
- "Task",
63
- "ShortTask",
60
+ "Actor",
61
+ "AsyncActor",
62
+ "Task", # Deprecated: Use Actor instead
63
+ "ShortTask", # Deprecated
64
64
  "SyncClient",
65
65
  # Core async classes
66
- "AsyncTask",
67
- "AsyncShortTask",
66
+ "AsyncTask", # Deprecated: Use AsyncActor instead
67
+ "AsyncShortTask", # Deprecated
68
68
  "AsyncClient",
69
69
  # Agent classes
70
70
  "TaskerAgent",
71
- # Functions
72
- "single_step",
73
- "async_single_step",
74
71
  # Async protocols
75
72
  "AsyncActionHandler",
76
73
  "AsyncImageProvider",
@@ -8,10 +8,11 @@
8
8
 
9
9
  import logging
10
10
 
11
- from .. import AsyncTask
11
+ from .. import AsyncActor
12
12
  from ..types import (
13
13
  AsyncActionHandler,
14
14
  AsyncImageProvider,
15
+ AsyncStepObserver,
15
16
  )
16
17
 
17
18
  logger = logging.getLogger(__name__)
@@ -27,12 +28,14 @@ class AsyncDefaultAgent:
27
28
  model: str = "lux-v1",
28
29
  max_steps: int = 30,
29
30
  temperature: float | None = None,
31
+ step_observer: AsyncStepObserver | None = None,
30
32
  ):
31
33
  self.api_key = api_key
32
34
  self.base_url = base_url
33
35
  self.model = model
34
36
  self.max_steps = max_steps
35
37
  self.temperature = temperature
38
+ self.step_observer = step_observer
36
39
 
37
40
  async def execute(
38
41
  self,
@@ -40,11 +43,11 @@ class AsyncDefaultAgent:
40
43
  action_handler: AsyncActionHandler,
41
44
  image_provider: AsyncImageProvider,
42
45
  ) -> bool:
43
- async with AsyncTask(
46
+ async with AsyncActor(
44
47
  api_key=self.api_key, base_url=self.base_url, model=self.model
45
- ) as self.task:
48
+ ) as self.actor:
46
49
  logger.info(f"Starting async task execution: {instruction}")
47
- await self.task.init_task(instruction, max_steps=self.max_steps)
50
+ await self.actor.init_task(instruction, max_steps=self.max_steps)
48
51
 
49
52
  for i in range(self.max_steps):
50
53
  logger.debug(f"Executing step {i + 1}/{self.max_steps}")
@@ -53,15 +56,28 @@ class AsyncDefaultAgent:
53
56
  image = await image_provider()
54
57
 
55
58
  # Get next step from OAGI
56
- step = await self.task.step(image, temperature=self.temperature)
59
+ step = await self.actor.step(image, temperature=self.temperature)
57
60
 
58
61
  # Log reasoning
59
62
  if step.reason:
60
- logger.debug(f"Step {i + 1} reasoning: {step.reason}")
63
+ logger.info(f"Step {i + 1}: {step.reason}")
64
+
65
+ # Notify observer if present
66
+ if self.step_observer and step.actions:
67
+ await self.step_observer.on_step(i + 1, step.reason, step.actions)
61
68
 
62
69
  # Execute actions if any
63
70
  if step.actions:
64
- logger.debug(f"Executing {len(step.actions)} actions")
71
+ logger.info(f"Actions ({len(step.actions)}):")
72
+ for action in step.actions:
73
+ count_suffix = (
74
+ f" x{action.count}"
75
+ if action.count and action.count > 1
76
+ else ""
77
+ )
78
+ logger.info(
79
+ f" [{action.type.value}] {action.argument}{count_suffix}"
80
+ )
65
81
  await action_handler(step.actions)
66
82
 
67
83
  # Check if task is complete
@@ -6,6 +6,7 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
  from oagi.agent.tasker import TaskerAgent
9
+ from oagi.types import AsyncStepObserver
9
10
 
10
11
  from .default import AsyncDefaultAgent
11
12
  from .protocol import AsyncAgent
@@ -19,6 +20,7 @@ def create_default_agent(
19
20
  model: str = "lux-v1",
20
21
  max_steps: int = 20,
21
22
  temperature: float = 0.1,
23
+ step_observer: AsyncStepObserver | None = None,
22
24
  ) -> AsyncAgent:
23
25
  return AsyncDefaultAgent(
24
26
  api_key=api_key,
@@ -26,6 +28,7 @@ def create_default_agent(
26
28
  model=model,
27
29
  max_steps=max_steps,
28
30
  temperature=temperature,
31
+ step_observer=step_observer,
29
32
  )
30
33
 
31
34
 
@@ -37,6 +40,7 @@ def create_planner_agent(
37
40
  max_steps: int = 30,
38
41
  temperature: float = 0.0,
39
42
  reflection_interval: int = 20,
43
+ step_observer: AsyncStepObserver | None = None,
40
44
  ) -> AsyncAgent:
41
45
  tasker = TaskerAgent(
42
46
  api_key=api_key,
@@ -45,6 +49,7 @@ def create_planner_agent(
45
49
  max_steps=max_steps,
46
50
  temperature=temperature,
47
51
  reflection_interval=reflection_interval,
52
+ step_observer=step_observer,
48
53
  )
49
54
  # tasker.set_task()
50
55
  return tasker
@@ -10,8 +10,8 @@ import logging
10
10
  from datetime import datetime
11
11
  from typing import Any
12
12
 
13
- from oagi import AsyncTask
14
- from oagi.types import AsyncActionHandler, AsyncImageProvider
13
+ from oagi import AsyncActor
14
+ from oagi.types import AsyncActionHandler, AsyncImageProvider, AsyncStepObserver
15
15
 
16
16
  from ..protocol import AsyncAgent
17
17
  from .memory import PlannerMemory
@@ -42,6 +42,7 @@ class TaskeeAgent(AsyncAgent):
42
42
  planner: Planner | None = None,
43
43
  external_memory: PlannerMemory | None = None,
44
44
  todo_index: int | None = None,
45
+ step_observer: AsyncStepObserver | None = None,
45
46
  ):
46
47
  """Initialize the taskee agent.
47
48
 
@@ -55,6 +56,7 @@ class TaskeeAgent(AsyncAgent):
55
56
  planner: Planner for planning and reflection
56
57
  external_memory: External memory from parent agent
57
58
  todo_index: Index of the todo being executed
59
+ step_observer: Optional observer for step tracking
58
60
  """
59
61
  self.api_key = api_key
60
62
  self.base_url = base_url
@@ -65,9 +67,10 @@ class TaskeeAgent(AsyncAgent):
65
67
  self.planner = planner or Planner()
66
68
  self.external_memory = external_memory
67
69
  self.todo_index = todo_index
70
+ self.step_observer = step_observer
68
71
 
69
72
  # Internal state
70
- self.task: AsyncTask | None = None
73
+ self.actor: AsyncActor | None = None
71
74
  self.current_todo: str = ""
72
75
  self.current_instruction: str = ""
73
76
  self.actions: list[Action] = []
@@ -135,10 +138,10 @@ class TaskeeAgent(AsyncAgent):
135
138
  )
136
139
  return False
137
140
  finally:
138
- # Clean up task
139
- if self.task:
140
- await self.task.close()
141
- self.task = None
141
+ # Clean up actor
142
+ if self.actor:
143
+ await self.actor.close()
144
+ self.actor = None
142
145
 
143
146
  async def _initial_plan(self, image_provider: AsyncImageProvider) -> None:
144
147
  """Generate initial plan for the todo.
@@ -199,17 +202,17 @@ class TaskeeAgent(AsyncAgent):
199
202
  logger.info(f"Executing subtask with max {max_steps} steps")
200
203
 
201
204
  # Use async with for automatic resource management
202
- async with AsyncTask(
205
+ async with AsyncActor(
203
206
  api_key=self.api_key,
204
207
  base_url=self.base_url,
205
208
  model=self.model,
206
209
  temperature=self.temperature,
207
- ) as task:
210
+ ) as actor:
208
211
  # Store reference for potential cleanup in execute's finally block
209
- self.task = task
212
+ self.actor = actor
210
213
 
211
- # Initialize task with current instruction
212
- await task.init_task(self.current_instruction)
214
+ # Initialize actor with current instruction
215
+ await actor.init_task(self.current_instruction)
213
216
 
214
217
  steps_taken = 0
215
218
  for step_num in range(max_steps):
@@ -218,7 +221,7 @@ class TaskeeAgent(AsyncAgent):
218
221
 
219
222
  # Get next step from OAGI
220
223
  try:
221
- step = await task.step(screenshot, instruction=None)
224
+ step = await actor.step(screenshot, instruction=None)
222
225
  except Exception as e:
223
226
  logger.error(f"Error getting step from OAGI: {e}")
224
227
  self._record_action(
@@ -228,8 +231,24 @@ class TaskeeAgent(AsyncAgent):
228
231
  )
229
232
  break
230
233
 
234
+ # Log reasoning
235
+ if step.reason:
236
+ logger.info(f"Step {self.total_actions + 1}: {step.reason}")
237
+
231
238
  # Record OAGI actions
232
239
  if step.actions:
240
+ # Log actions with details
241
+ logger.info(f"Actions ({len(step.actions)}):")
242
+ for action in step.actions:
243
+ count_suffix = (
244
+ f" x{action.count}"
245
+ if action.count and action.count > 1
246
+ else ""
247
+ )
248
+ logger.info(
249
+ f" [{action.type.value}] {action.argument}{count_suffix}"
250
+ )
251
+
233
252
  for action in step.actions:
234
253
  self._record_action(
235
254
  action_type=action.type.lower(),
@@ -237,6 +256,12 @@ class TaskeeAgent(AsyncAgent):
237
256
  reasoning=step.reason,
238
257
  )
239
258
 
259
+ # Notify observer if present
260
+ if self.step_observer:
261
+ await self.step_observer.on_step(
262
+ self.total_actions + 1, step.reason, step.actions
263
+ )
264
+
240
265
  # Execute actions
241
266
  await action_handler(step.actions)
242
267
  self.total_actions += len(step.actions)
@@ -255,9 +280,9 @@ class TaskeeAgent(AsyncAgent):
255
280
  logger.info("Reflection interval reached")
256
281
  break
257
282
 
258
- # Task will be automatically closed by async with context manager
283
+ # Actor will be automatically closed by async with context manager
259
284
  # Clear reference after context manager closes it
260
- self.task = None
285
+ self.actor = None
261
286
  return steps_taken
262
287
 
263
288
  async def _reflect_and_decide(self, image_provider: AsyncImageProvider) -> bool:
@@ -9,7 +9,7 @@
9
9
  import logging
10
10
  from typing import Any
11
11
 
12
- from oagi.types import AsyncActionHandler, AsyncImageProvider
12
+ from oagi.types import AsyncActionHandler, AsyncImageProvider, AsyncStepObserver
13
13
 
14
14
  from ..protocol import AsyncAgent
15
15
  from .memory import PlannerMemory
@@ -39,6 +39,7 @@ class TaskerAgent(AsyncAgent):
39
39
  temperature: float = 0.0,
40
40
  reflection_interval: int = 20,
41
41
  planner: Planner | None = None,
42
+ step_observer: AsyncStepObserver | None = None,
42
43
  ):
43
44
  """Initialize the tasker agent.
44
45
 
@@ -50,6 +51,7 @@ class TaskerAgent(AsyncAgent):
50
51
  temperature: Sampling temperature
51
52
  reflection_interval: Actions before reflection
52
53
  planner: Planner for planning and reflection
54
+ step_observer: Optional observer for step tracking
53
55
  """
54
56
  self.api_key = api_key
55
57
  self.base_url = base_url
@@ -58,6 +60,7 @@ class TaskerAgent(AsyncAgent):
58
60
  self.temperature = temperature
59
61
  self.reflection_interval = reflection_interval
60
62
  self.planner = planner or Planner()
63
+ self.step_observer = step_observer
61
64
 
62
65
  # Memory for tracking workflow
63
66
  self.memory = PlannerMemory()
@@ -174,6 +177,7 @@ class TaskerAgent(AsyncAgent):
174
177
  planner=self.planner,
175
178
  external_memory=self.memory, # Share memory with child
176
179
  todo_index=todo_index, # Pass the todo index
180
+ step_observer=self.step_observer, # Pass step observer
177
181
  )
178
182
 
179
183
  self.current_todo_index = todo_index