oagi-core 0.9.0__py3-none-any.whl → 0.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
oagi/__init__.py CHANGED
@@ -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",
oagi/agent/default.py CHANGED
@@ -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
oagi/agent/factories.py CHANGED
@@ -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
oagi/cli/agent.py CHANGED
@@ -10,9 +10,14 @@ import argparse
10
10
  import asyncio
11
11
  import os
12
12
  import sys
13
+ import time
14
+ import traceback
13
15
 
14
16
  from oagi.exceptions import check_optional_dependency
15
17
 
18
+ from .display import display_step_table
19
+ from .tracking import StepTracker
20
+
16
21
 
17
22
  def add_agent_parser(subparsers: argparse._SubParsersAction) -> None:
18
23
  agent_parser = subparsers.add_parser("agent", help="Agent execution commands")
@@ -79,7 +84,10 @@ def run_agent(args: argparse.Namespace) -> None:
79
84
  temperature = args.temperature if args.temperature is not None else 0.0
80
85
  mode = args.mode or "actor"
81
86
 
82
- # Create agent
87
+ # Create step tracker
88
+ step_tracker = StepTracker()
89
+
90
+ # Create agent with step tracker
83
91
  agent = create_agent(
84
92
  mode=mode,
85
93
  api_key=api_key,
@@ -87,6 +95,7 @@ def run_agent(args: argparse.Namespace) -> None:
87
95
  model=model,
88
96
  max_steps=max_steps,
89
97
  temperature=temperature,
98
+ step_observer=step_tracker,
90
99
  )
91
100
 
92
101
  # Create handlers
@@ -99,7 +108,10 @@ def run_agent(args: argparse.Namespace) -> None:
99
108
  )
100
109
  print("-" * 60)
101
110
 
102
- # Run agent
111
+ start_time = time.time()
112
+ success = False
113
+ interrupted = False
114
+
103
115
  try:
104
116
  success = asyncio.run(
105
117
  agent.execute(
@@ -108,18 +120,22 @@ def run_agent(args: argparse.Namespace) -> None:
108
120
  image_provider=image_provider,
109
121
  )
110
122
  )
111
-
112
- print("-" * 60)
113
- if success:
114
- print("Task completed successfully!")
115
- sys.exit(0)
116
- else:
117
- print("Task failed or reached max steps without completion.")
118
- sys.exit(1)
119
-
120
123
  except KeyboardInterrupt:
121
- print("\nAgent execution interrupted.")
122
- sys.exit(130)
124
+ print("\nAgent execution interrupted by user (Ctrl+C)")
125
+ interrupted = True
123
126
  except Exception as e:
124
- print(f"Error during agent execution: {e}", file=sys.stderr)
125
- sys.exit(1)
127
+ print(f"\nError during agent execution: {e}", file=sys.stderr)
128
+ traceback.print_exc()
129
+ finally:
130
+ duration = time.time() - start_time
131
+
132
+ if step_tracker.steps:
133
+ print("\n" + "=" * 60)
134
+ display_step_table(step_tracker.steps, success, duration)
135
+ else:
136
+ print("\nNo steps were executed.")
137
+
138
+ if interrupted:
139
+ sys.exit(130)
140
+ elif not success:
141
+ sys.exit(1)
oagi/cli/display.py ADDED
@@ -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
+
9
+ from rich.console import Console
10
+ from rich.table import Table
11
+
12
+ from .tracking import StepData
13
+
14
+
15
+ def display_step_table(
16
+ steps: list[StepData], success: bool, duration: float | None = None
17
+ ):
18
+ console = Console()
19
+
20
+ table = Table(title="Agent Execution Summary", show_lines=True)
21
+ table.add_column("Step", justify="center", style="cyan", width=6)
22
+ table.add_column("Reasoning", style="white")
23
+ table.add_column("Actions", style="yellow", width=35)
24
+ table.add_column("Status", justify="center", width=8)
25
+
26
+ for step in steps:
27
+ reason = step.reasoning or "N/A"
28
+
29
+ actions_display = []
30
+ for action in step.actions[:3]:
31
+ arg = action.argument[:20] if action.argument else ""
32
+ actions_display.append(f"{action.type.value}({arg})")
33
+
34
+ actions_str = ", ".join(actions_display)
35
+ if len(step.actions) > 3:
36
+ actions_str += f" (+{len(step.actions) - 3} more)"
37
+
38
+ status_display = "✓" if step.status == "complete" else "→"
39
+
40
+ table.add_row(
41
+ str(step.step_num),
42
+ reason,
43
+ actions_str,
44
+ status_display,
45
+ )
46
+
47
+ console.print(table)
48
+
49
+ status_text = "Success" if success else "Failed/Interrupted"
50
+ console.print(
51
+ f"\nTotal Steps: {len(steps)} | Status: {status_text}",
52
+ style="bold",
53
+ )
54
+
55
+ if duration:
56
+ console.print(f"Duration: {duration:.2f}s")
oagi/cli/tracking.py ADDED
@@ -0,0 +1,45 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) OpenAGI Foundation
3
+ # All rights reserved.
4
+ #
5
+ # This file is part of the official API project.
6
+ # Licensed under the MIT License.
7
+ # -----------------------------------------------------------------------------
8
+
9
+ from dataclasses import dataclass
10
+ from datetime import datetime
11
+
12
+ from oagi.types import Action
13
+
14
+
15
+ @dataclass
16
+ class StepData:
17
+ step_num: int
18
+ timestamp: datetime
19
+ reasoning: str | None
20
+ actions: list[Action]
21
+ action_count: int
22
+ status: str
23
+
24
+
25
+ class StepTracker:
26
+ """Tracks agent step execution by implementing AsyncStepObserver protocol."""
27
+
28
+ def __init__(self):
29
+ self.steps: list[StepData] = []
30
+
31
+ async def on_step(
32
+ self,
33
+ step_num: int,
34
+ reasoning: str | None,
35
+ actions: list[Action],
36
+ ) -> None:
37
+ step_data = StepData(
38
+ step_num=step_num,
39
+ timestamp=datetime.now(),
40
+ reasoning=reasoning,
41
+ actions=actions,
42
+ action_count=len(actions),
43
+ status="running",
44
+ )
45
+ self.steps.append(step_data)
@@ -0,0 +1,24 @@
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
+ from oagi.handler.async_pyautogui_action_handler import AsyncPyautoguiActionHandler
9
+ from oagi.handler.async_screenshot_maker import AsyncScreenshotMaker
10
+ from oagi.handler.pil_image import PILImage
11
+ from oagi.handler.pyautogui_action_handler import (
12
+ PyautoguiActionHandler,
13
+ PyautoguiConfig,
14
+ )
15
+ from oagi.handler.screenshot_maker import ScreenshotMaker
16
+
17
+ __all__ = [
18
+ "PILImage",
19
+ "PyautoguiActionHandler",
20
+ "PyautoguiConfig",
21
+ "AsyncPyautoguiActionHandler",
22
+ "ScreenshotMaker",
23
+ "AsyncScreenshotMaker",
24
+ ]
@@ -8,8 +8,8 @@
8
8
 
9
9
  import asyncio
10
10
 
11
+ from ..types import Action
11
12
  from .pyautogui_action_handler import PyautoguiActionHandler, PyautoguiConfig
12
- from .types import Action
13
13
 
14
14
 
15
15
  class AsyncPyautoguiActionHandler:
@@ -8,8 +8,8 @@
8
8
 
9
9
  import asyncio
10
10
 
11
+ from ..types import Image, ImageConfig
11
12
  from .screenshot_maker import ScreenshotMaker
12
- from .types import Image, ImageConfig
13
13
 
14
14
 
15
15
  class AsyncScreenshotMaker:
@@ -8,8 +8,8 @@
8
8
 
9
9
  import io
10
10
 
11
- from .exceptions import check_optional_dependency
12
- from .types.models.image_config import ImageConfig
11
+ from ..exceptions import check_optional_dependency
12
+ from ..types.models.image_config import ImageConfig
13
13
 
14
14
  check_optional_dependency("PIL", "PILImage", "desktop")
15
15
  from PIL import Image as PILImageLib # noqa: E402
@@ -11,8 +11,8 @@ import time
11
11
 
12
12
  from pydantic import BaseModel, Field
13
13
 
14
- from .exceptions import check_optional_dependency
15
- from .types import Action, ActionType
14
+ from ..exceptions import check_optional_dependency
15
+ from ..types import Action, ActionType
16
16
 
17
17
  check_optional_dependency("pyautogui", "PyautoguiActionHandler", "desktop")
18
18
  import pyautogui # noqa: E402
@@ -8,9 +8,9 @@
8
8
 
9
9
  from typing import Optional
10
10
 
11
+ from ..types import Image
12
+ from ..types.models.image_config import ImageConfig
11
13
  from .pil_image import PILImage
12
- from .types import Image
13
- from .types.models.image_config import ImageConfig
14
14
 
15
15
 
16
16
  class ScreenshotMaker:
oagi/logging.py CHANGED
@@ -44,4 +44,12 @@ def get_logger(name: str) -> logging.Logger:
44
44
  # Always update level in case environment variable changed
45
45
  oagi_root.setLevel(level)
46
46
 
47
+ # Suppress verbose httpx logs unless DEBUG level is enabled
48
+ # httpx logs every HTTP request at INFO level by default
49
+ httpx_logger = logging.getLogger("httpx")
50
+ if level == logging.DEBUG:
51
+ httpx_logger.setLevel(logging.DEBUG)
52
+ else:
53
+ httpx_logger.setLevel(logging.WARNING)
54
+
47
55
  return logger
oagi/task/__init__.py CHANGED
@@ -6,9 +6,16 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- from .async_ import AsyncTask
9
+ from .async_ import AsyncActor, AsyncTask
10
10
  from .async_short import AsyncShortTask
11
11
  from .short import ShortTask
12
- from .sync import Task
12
+ from .sync import Actor, Task
13
13
 
14
- __all__ = ["Task", "AsyncTask", "ShortTask", "AsyncShortTask"]
14
+ __all__ = [
15
+ "Actor",
16
+ "AsyncActor",
17
+ "Task", # Deprecated: Use Actor instead
18
+ "AsyncTask", # Deprecated: Use AsyncActor instead
19
+ "ShortTask", # Deprecated
20
+ "AsyncShortTask", # Deprecated
21
+ ]
oagi/task/async_.py CHANGED
@@ -6,6 +6,8 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ import warnings
10
+
9
11
  from ..client import AsyncClient
10
12
  from ..logging import get_logger
11
13
  from ..types import Image, Step
@@ -14,7 +16,7 @@ from .base import BaseTask
14
16
  logger = get_logger("async_task")
15
17
 
16
18
 
17
- class AsyncTask(BaseTask):
19
+ class AsyncActor(BaseTask):
18
20
  """Async base class for task automation with the OAGI API."""
19
21
 
20
22
  def __init__(
@@ -95,3 +97,26 @@ class AsyncTask(BaseTask):
95
97
 
96
98
  async def __aexit__(self, exc_type, exc_val, exc_tb):
97
99
  await self.close()
100
+
101
+
102
+ class AsyncTask(AsyncActor):
103
+ """Deprecated: Use AsyncActor instead.
104
+
105
+ This class is deprecated and will be removed in a future version.
106
+ Please use AsyncActor instead.
107
+ """
108
+
109
+ def __init__(
110
+ self,
111
+ api_key: str | None = None,
112
+ base_url: str | None = None,
113
+ model: str = "vision-model-v1",
114
+ temperature: float | None = None,
115
+ ):
116
+ warnings.warn(
117
+ "AsyncTask is deprecated and will be removed in a future version. "
118
+ "Please use AsyncActor instead.",
119
+ DeprecationWarning,
120
+ stacklevel=2,
121
+ )
122
+ super().__init__(api_key, base_url, model, temperature)
oagi/task/async_short.py CHANGED
@@ -6,16 +6,22 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ import warnings
10
+
9
11
  from ..logging import get_logger
10
12
  from ..types import AsyncActionHandler, AsyncImageProvider
11
- from .async_ import AsyncTask
13
+ from .async_ import AsyncActor
12
14
  from .base import BaseAutoMode
13
15
 
14
16
  logger = get_logger("async_short_task")
15
17
 
16
18
 
17
- class AsyncShortTask(AsyncTask, BaseAutoMode):
18
- """Async task implementation with automatic mode for short-duration tasks."""
19
+ class AsyncShortTask(AsyncActor, BaseAutoMode):
20
+ """Deprecated: This class is deprecated and will be removed in a future version.
21
+
22
+ Async task implementation with automatic mode for short-duration tasks.
23
+ Please use AsyncActor directly with custom automation logic instead.
24
+ """
19
25
 
20
26
  def __init__(
21
27
  self,
@@ -24,6 +30,12 @@ class AsyncShortTask(AsyncTask, BaseAutoMode):
24
30
  model: str = "vision-model-v1",
25
31
  temperature: float | None = None,
26
32
  ):
33
+ warnings.warn(
34
+ "AsyncShortTask is deprecated and will be removed in a future version. "
35
+ "Please use AsyncActor with custom automation logic instead.",
36
+ DeprecationWarning,
37
+ stacklevel=2,
38
+ )
27
39
  super().__init__(
28
40
  api_key=api_key, base_url=base_url, model=model, temperature=temperature
29
41
  )
oagi/task/base.py CHANGED
@@ -45,7 +45,9 @@ class BaseTask:
45
45
  task_desc: Task description
46
46
  max_steps: Maximum number of steps
47
47
  """
48
+ self.task_id = uuid4().hex
48
49
  self.task_description = task_desc
50
+ self.message_history = []
49
51
  logger.info(f"Task initialized: '{task_desc}' (max_steps: {max_steps})")
50
52
 
51
53
  def _validate_step_preconditions(self):
oagi/task/short.py CHANGED
@@ -6,16 +6,22 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ import warnings
10
+
9
11
  from ..logging import get_logger
10
12
  from ..types import ActionHandler, ImageProvider
11
13
  from .base import BaseAutoMode
12
- from .sync import Task
14
+ from .sync import Actor
13
15
 
14
16
  logger = get_logger("short_task")
15
17
 
16
18
 
17
- class ShortTask(Task, BaseAutoMode):
18
- """Task implementation with automatic mode for short-duration tasks."""
19
+ class ShortTask(Actor, BaseAutoMode):
20
+ """Deprecated: This class is deprecated and will be removed in a future version.
21
+
22
+ Task implementation with automatic mode for short-duration tasks.
23
+ Please use Actor directly with custom automation logic instead.
24
+ """
19
25
 
20
26
  def __init__(
21
27
  self,
@@ -24,6 +30,12 @@ class ShortTask(Task, BaseAutoMode):
24
30
  model: str = "vision-model-v1",
25
31
  temperature: float | None = None,
26
32
  ):
33
+ warnings.warn(
34
+ "ShortTask is deprecated and will be removed in a future version. "
35
+ "Please use Actor with custom automation logic instead.",
36
+ DeprecationWarning,
37
+ stacklevel=2,
38
+ )
27
39
  super().__init__(
28
40
  api_key=api_key, base_url=base_url, model=model, temperature=temperature
29
41
  )
oagi/task/sync.py CHANGED
@@ -6,6 +6,8 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ import warnings
10
+
9
11
  from ..client import SyncClient
10
12
  from ..logging import get_logger
11
13
  from ..types import Image, Step
@@ -14,7 +16,7 @@ from .base import BaseTask
14
16
  logger = get_logger("task")
15
17
 
16
18
 
17
- class Task(BaseTask):
19
+ class Actor(BaseTask):
18
20
  """Base class for task automation with the OAGI API."""
19
21
 
20
22
  def __init__(
@@ -95,3 +97,26 @@ class Task(BaseTask):
95
97
 
96
98
  def __exit__(self, exc_type, exc_val, exc_tb):
97
99
  self.close()
100
+
101
+
102
+ class Task(Actor):
103
+ """Deprecated: Use Actor instead.
104
+
105
+ This class is deprecated and will be removed in a future version.
106
+ Please use Actor instead.
107
+ """
108
+
109
+ def __init__(
110
+ self,
111
+ api_key: str | None = None,
112
+ base_url: str | None = None,
113
+ model: str = "vision-model-v1",
114
+ temperature: float | None = None,
115
+ ):
116
+ warnings.warn(
117
+ "Task is deprecated and will be removed in a future version. "
118
+ "Please use Actor instead.",
119
+ DeprecationWarning,
120
+ stacklevel=2,
121
+ )
122
+ super().__init__(api_key, base_url, model, temperature)
oagi/types/__init__.py CHANGED
@@ -12,6 +12,7 @@ from .async_image_provider import AsyncImageProvider
12
12
  from .image import Image
13
13
  from .image_provider import ImageProvider
14
14
  from .models import Action, ActionType, ImageConfig, Step
15
+ from .step_observer import AsyncStepObserver
15
16
  from .url_image import URLImage
16
17
 
17
18
  __all__ = [
@@ -24,5 +25,6 @@ __all__ = [
24
25
  "AsyncActionHandler",
25
26
  "ImageProvider",
26
27
  "AsyncImageProvider",
28
+ "AsyncStepObserver",
27
29
  "URLImage",
28
30
  ]
@@ -0,0 +1,34 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) OpenAGI Foundation
3
+ # All rights reserved.
4
+ #
5
+ # This file is part of the official API project.
6
+ # Licensed under the MIT License.
7
+ # -----------------------------------------------------------------------------
8
+
9
+ from typing import Protocol
10
+
11
+ from .models import Action
12
+
13
+
14
+ class AsyncStepObserver(Protocol):
15
+ """Protocol for observing agent step execution.
16
+
17
+ Observers receive step information (reasoning and actions) as agents
18
+ execute tasks, enabling tracking, logging, or other side effects.
19
+ """
20
+
21
+ async def on_step(
22
+ self,
23
+ step_num: int,
24
+ reasoning: str | None,
25
+ actions: list[Action],
26
+ ) -> None:
27
+ """Called when an agent executes a step.
28
+
29
+ Args:
30
+ step_num: The step number (1-indexed)
31
+ reasoning: The reasoning/thinking for this step (if available)
32
+ actions: The list of actions being executed in this step
33
+ """
34
+ ...
@@ -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
@@ -1,33 +1,34 @@
1
- oagi/__init__.py,sha256=2yFfGqF5Ve2ZmQHYNHvlTQJIENUV2j5AV_fROsUrbyU,2998
2
- oagi/async_pyautogui_action_handler.py,sha256=F-lKyePCONWI03WnSxpX_QwxONbvnfdQu51wTod6mdw,1614
3
- oagi/async_screenshot_maker.py,sha256=pI-dbLcYOzcO1ffgTmozAdbYJQNBPKA7hmqj1RxEmIY,1688
4
- oagi/async_single_step.py,sha256=FxOSoZKKegHx0by41a4qrJDPoYZV0qZKtdTNMU8Uqz4,2955
1
+ oagi/__init__.py,sha256=cSqJ61OyscGJLHBCn53cS4PrCKC4DQl5xRDNkGR0TXo,3041
5
2
  oagi/exceptions.py,sha256=Rco37GQTPYUfc2vRO3hozxPF_s8mKFDpFvBg2UKWo3Y,3066
6
- oagi/logging.py,sha256=YaG-UQWjqXJTfk6MsxcX_xfPVeVCq2ryIH1zwgR2_fQ,1455
7
- oagi/pil_image.py,sha256=xs6nDRyjTCaoeIMb3GV5d4U6dbG5M5jr2TdMc57eJMo,4078
8
- oagi/pyautogui_action_handler.py,sha256=N-4XcCV8f92ViuwXnpgk3ILGrlhR_8L1CKkGq_ub5gQ,9952
9
- oagi/screenshot_maker.py,sha256=sVuW7jn-K4FmLhmYI-akdNI-UVcTeBzh9P1_qJhoq1s,1282
10
- oagi/single_step.py,sha256=62Zip4Uql6E-ZIX6vAlrBoveKqrnABzGqHdLCzju4ag,3138
3
+ oagi/logging.py,sha256=YT3KCMFj5fzO98R9xlDDgfSotUuz1xRD6OZeYM2rKoo,1760
11
4
  oagi/agent/__init__.py,sha256=JU9zuWuDzpzitsVJB4z5ddvx8RMm5nbP-bjUCL1Sfvo,834
12
- oagi/agent/default.py,sha256=XJXbltDOak3Wer92MXiocLgD9_y0OWJ88isWNOFhaLk,2397
13
- oagi/agent/factories.py,sha256=JsOqzUWY2_MlL16XznLR8MrWUqgOQTmAyDOvtsA1zvY,1386
5
+ oagi/agent/default.py,sha256=FaaNTssDt5rcuEUppznATqNOTTEJFThcxbBpPChzwnU,3108
6
+ oagi/agent/factories.py,sha256=eE0hcXyJX4dk2nvRRlEvQPJqkBraeIaT7nXiED2lH_Q,1605
14
7
  oagi/agent/protocol.py,sha256=IQJGiMN4yZIacrh5e9JQsoM9TyHb8wJRQR4LAk8dSA0,1615
15
8
  oagi/agent/registry.py,sha256=4oG65E_bV47Xl6F-HX9KaVoV0pcoC1uRRDU4RT_m3uU,4841
16
9
  oagi/agent/tasker/__init__.py,sha256=faOC5ONY8ZKr4CjofC6HYg1WKWc1UiaGB9VHy8W280M,800
17
10
  oagi/agent/tasker/memory.py,sha256=JsJjUMpnJoKW4VFzd8FI4M-FhnEihTecL61KVgO_YBI,6051
18
11
  oagi/agent/tasker/models.py,sha256=VzvHB5hLv6qyYcyNiojVIEDlTzeGE4Quswk4EVIbzoI,2180
19
12
  oagi/agent/tasker/planner.py,sha256=j0Zhk6kw0LFtxkpjFhmeaTBxZfKLf3qqCNpGAuMuODw,13650
20
- oagi/agent/tasker/taskee_agent.py,sha256=L_5JvWQLVeqY35Xclv7YBOb0gHnGMZ4tJdbskGLc-_o,12966
21
- oagi/agent/tasker/tasker_agent.py,sha256=PzfsBZvMCH1QMRXDMPQtezw4rX_PfOj7sXSsDAH0U6g,10705
13
+ oagi/agent/tasker/taskee_agent.py,sha256=9t_uIilH2KCnkv013mIfk2VPPNKz6wJtTyjEJLvZOzQ,14093
14
+ oagi/agent/tasker/tasker_agent.py,sha256=d4khAfd1_Ra1KP7Y2un8BwUBeGh-Frwp2xWc7prI6F4,10954
22
15
  oagi/cli/__init__.py,sha256=aDnJViTseShpo5fdGPTj-ELysZhmdvB6Z8mEj2D-_N4,359
23
- oagi/cli/agent.py,sha256=U7Yjmfi7aGt--iisuylg0C2-17bVB3tTBq2sXYU0Gtg,4020
16
+ oagi/cli/agent.py,sha256=q0dLyjrzT3PkZreaXSqpHN_rH5fAB_jHyLonPy-V6hk,4453
17
+ oagi/cli/display.py,sha256=rkAxuHa40ZtKdmvwARev1rgyfsNyVvQ-J6RdjOZIPwc,1729
24
18
  oagi/cli/main.py,sha256=faHns0HaQCGyylDn2YZLpjQESuEiMYjoQVoMkt8FsH4,2292
25
19
  oagi/cli/server.py,sha256=Z1ic8r55yaeQBFRCsMNZStC1jRiJdnDGqe9On9LmFzQ,3031
20
+ oagi/cli/tracking.py,sha256=jPH6QDUUwnfZ8bjQU6deofBmBflTEOOCINwinQJz9OI,1147
26
21
  oagi/cli/utils.py,sha256=QvDyoP0nU9aq4ORjnvJJAGRECmjh9WAmilKuk6zOGM8,2615
27
22
  oagi/client/__init__.py,sha256=F9DShPUdb6vZYmN1fpM1VYzp4MWqUao_e_R1KYmM4Q4,410
28
23
  oagi/client/async_.py,sha256=t-GPHcz6xbHx_RPFv1V_hwZ1_f-O9ONH-Ahr0w-Nz8M,11046
29
24
  oagi/client/base.py,sha256=TlZk4LaYFlOQFmTTgTDzZ1XRAixqNO0pCwgJ7VhZOSU,17101
30
25
  oagi/client/sync.py,sha256=QKd6nTUXtyn1Am8YlFcpsoLh1KuHhQgbMemIkb7r39g,10882
26
+ oagi/handler/__init__.py,sha256=Ha11L42K33K3L9S4lQ10UC0DnD5g6egtQUsJpS_tKgg,835
27
+ oagi/handler/async_pyautogui_action_handler.py,sha256=hQzseR1yBD0QMpgsEVNsUmuApGVAIIyGYD06BXd82Dc,1615
28
+ oagi/handler/async_screenshot_maker.py,sha256=8QCtUV59ozpOpvkqhUMb8QDI2qje2gsoFT1qB60tfJM,1689
29
+ oagi/handler/pil_image.py,sha256=yUcAoGBL-aZ0PCjSaAmQsDwtyzjldXHqXQp_OYRk6e4,4080
30
+ oagi/handler/pyautogui_action_handler.py,sha256=rhQAes81-hR5KoFiB4Ph6Cw5r04vYiqvZx64eA31pBw,9954
31
+ oagi/handler/screenshot_maker.py,sha256=j1jTW-awx3vAnb1N5_FIMBC0Z-rNVQbiBP-S6Gh5dlE,1284
31
32
  oagi/server/__init__.py,sha256=uZx8u3vJUb87kkNzwmmVrgAgbqRu0WxyMIQCLSx56kk,452
32
33
  oagi/server/agent_wrappers.py,sha256=4f6ZKvqy9TDA57QRHGjAQVhpHmPE5QNeewmmURg5Ajo,3288
33
34
  oagi/server/config.py,sha256=RstTWbPwWCfW9ZRJcns3uCbdhXxuUnerKjxR1pCGbqY,1602
@@ -35,26 +36,27 @@ oagi/server/main.py,sha256=jnTxk7Prc5CzlsUnkBNJp4MOoYN-7HN_Be_m1d3COa8,4829
35
36
  oagi/server/models.py,sha256=E0R80zIz-YLpwx4VQyADQEnM89ZY9bXmjuswfhCuqMc,2595
36
37
  oagi/server/session_store.py,sha256=UI14NiApAwvZWmMOG4SvPE2WkbGkNTHToZhTXQjN2_U,3624
37
38
  oagi/server/socketio_server.py,sha256=UeNm9bemYMZqtYWp3i09BLUyEWW6t8yTkl2pjpSeT_M,14359
38
- oagi/task/__init__.py,sha256=kvB8ENQ3iII9Uzqa9SSIxBv5JFKv44j2T6J-_Qc8A-4,494
39
- oagi/task/async_.py,sha256=QDXaw3wAI8Utbph_kB1a3Elv2aeZwPnv2R7wT16LDXo,3242
40
- oagi/task/async_short.py,sha256=h7Kchl4opUjyKQd_0Vd7DHWoBOTcYqN1lPdGeyTjoq8,2324
41
- oagi/task/base.py,sha256=gUpWWhgbkrN17pmZNISmyzxLedhWZ39wVt7fRhH6JDM,4378
42
- oagi/task/short.py,sha256=pjhoYN_a5KS_cGKfXbB575wdw-nx9ZdzJTplMr3sgqs,2148
43
- oagi/task/sync.py,sha256=_tMjw4Gjyk3wKCD_q7Pwvug0-DMD7DalXZocrREZogc,3135
44
- oagi/types/__init__.py,sha256=j-ShAARBbz-fGgkaQj5j_xyhFGM4XWnUTp-h3xhm9Bo,814
39
+ oagi/task/__init__.py,sha256=g_8_7ZLDLKuCGzyrB42OzY3gSOjd_SxzkJW3_pf-PXs,662
40
+ oagi/task/async_.py,sha256=IwoLy0SHLNI7k6I5Ja0WmWa8U-SDLogoM-qHFjbVISU,3924
41
+ oagi/task/async_short.py,sha256=LjgWotSxyuTRpNNFsAhAP0Y0raze0GHyoWqthLaPoS8,2755
42
+ oagi/task/base.py,sha256=Udp_Yl5GVUWR7RtayrQlwa8Yg_Nrsyal3mGEkaG8FmE,4447
43
+ oagi/task/short.py,sha256=mgXao6AXuR8XvHwnf3KjzsCm1PZRLzKg1R-2JmS2yoM,2564
44
+ oagi/task/sync.py,sha256=Ag171gJxcWkLgmna4X5Ipgf3qEDDj2JnZEQ9b-mH0mM,3787
45
+ oagi/types/__init__.py,sha256=Vz6JArE8XvBWlES8CVLy-Nx97gooh1OSsltBL6iaFiM,884
45
46
  oagi/types/action_handler.py,sha256=NH8E-m5qpGqWcXzTSWfF7W0Xdp8SkzJsbhCmQ0B96cg,1075
46
47
  oagi/types/async_action_handler.py,sha256=k1AaqSkFcXlxwW8sn-w0WFHGsIqHFLbcOPrkknmSVug,1116
47
48
  oagi/types/async_image_provider.py,sha256=wnhRyPtTmuALt45Qore74-RCkP5yxU9sZGjvOzFqzOk,1170
48
49
  oagi/types/image.py,sha256=KgPCCTJ6D5vHIaGZdbTE7eQEa1WlT6G9tf59ZuUCV2U,537
49
50
  oagi/types/image_provider.py,sha256=oYFdOYznrK_VOR9egzOjw5wFM5w8EY2sY01pH0ANAgU,1112
51
+ oagi/types/step_observer.py,sha256=KDw7yQxA_I6T2DqElspAOMa8rBJTYFWBNHfC-9NmasM,1025
50
52
  oagi/types/url_image.py,sha256=iOwtXj2uwY6dVtDP7uvQLPvK-aTxkdrzhw_R4C6GwBw,1334
51
53
  oagi/types/models/__init__.py,sha256=I86Z2moM8hCog_1K1FG_uATcBmWFv_UFetLAjzPzWAY,742
52
54
  oagi/types/models/action.py,sha256=hh6mRRSSWgrW4jpZo71zGMCOcZpV5_COu4148uG6G48,967
53
55
  oagi/types/models/client.py,sha256=fCN18DBq5XDjNyYB8w-2dFeQ_K9ywwdyh-rXa0GToU4,1357
54
56
  oagi/types/models/image_config.py,sha256=tl6abVg_-IAPLwpaWprgknXu7wRWriMg-AEVyUX73v0,1567
55
57
  oagi/types/models/step.py,sha256=RSI4H_2rrUBq_xyCoWKaq7JHdJWNobtQppaKC1l0aWU,471
56
- oagi_core-0.9.0.dist-info/METADATA,sha256=4GekQr0XrNc9sDArtojzQTS6SYXNJz9ax8jQtDW-hMY,8187
57
- oagi_core-0.9.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
58
- oagi_core-0.9.0.dist-info/entry_points.txt,sha256=zzgsOSWX6aN3KUB0Z1it8DMxFFBJBqmZVqMVAJRjYuw,44
59
- oagi_core-0.9.0.dist-info/licenses/LICENSE,sha256=sy5DLA2M29jFT4UfWsuBF9BAr3FnRkYtnAu6oDZiIf8,1075
60
- oagi_core-0.9.0.dist-info/RECORD,,
58
+ oagi_core-0.9.1.dist-info/METADATA,sha256=zJ3xNe4fGIUHAff90wp0s_d98QsjEunz848CWcoQd2w,7543
59
+ oagi_core-0.9.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
60
+ oagi_core-0.9.1.dist-info/entry_points.txt,sha256=zzgsOSWX6aN3KUB0Z1it8DMxFFBJBqmZVqMVAJRjYuw,44
61
+ oagi_core-0.9.1.dist-info/licenses/LICENSE,sha256=sy5DLA2M29jFT4UfWsuBF9BAr3FnRkYtnAu6oDZiIf8,1075
62
+ oagi_core-0.9.1.dist-info/RECORD,,
oagi/async_single_step.py DELETED
@@ -1,85 +0,0 @@
1
- # -----------------------------------------------------------------------------
2
- # Copyright (c) OpenAGI Foundation
3
- # All rights reserved.
4
- #
5
- # This file is part of the official API project.
6
- # Licensed under the MIT License.
7
- # -----------------------------------------------------------------------------
8
-
9
- from pathlib import Path
10
-
11
- from .task import AsyncTask
12
- from .types import Image, Step
13
-
14
-
15
- async def async_single_step(
16
- task_description: str,
17
- screenshot: str | bytes | Path | Image,
18
- instruction: str | None = None,
19
- api_key: str | None = None,
20
- base_url: str | None = None,
21
- temperature: float | None = None,
22
- ) -> Step:
23
- """
24
- Perform a single-step inference asynchronously without maintaining task state.
25
-
26
- This is useful for one-off analyses where you don't need to maintain
27
- a conversation or task context across multiple steps.
28
-
29
- Args:
30
- task_description: Description of the task to perform
31
- screenshot: Screenshot as Image, bytes, or file path
32
- instruction: Optional additional instruction for the task
33
- api_key: OAGI API key (uses environment variable if not provided)
34
- base_url: OAGI base URL (uses environment variable if not provided)
35
- temperature: Sampling temperature (0.0-2.0) for LLM inference
36
-
37
- Returns:
38
- Step: Object containing reasoning, actions, and completion status
39
-
40
- Example:
41
- >>> # Using with bytes
42
- >>> import asyncio
43
- >>> async def main():
44
- ... with open("screenshot.png", "rb") as f:
45
- ... screenshot_bytes = f.read()
46
- ... step = await async_single_step(
47
- ... "Click the submit button",
48
- ... screenshot=screenshot_bytes
49
- ... )
50
- ... print(f"Actions: {step.actions}")
51
- >>> asyncio.run(main())
52
-
53
- >>> # Using with file path
54
- >>> step = await async_single_step(
55
- ... "Find the search box",
56
- ... screenshot="screenshot.png"
57
- ... )
58
-
59
- >>> # Using with PILImage
60
- >>> image = PILImage.from_file("screenshot.png")
61
- >>> step = await async_single_step(
62
- ... "Click next page",
63
- ... screenshot=image
64
- ... )
65
- """
66
- # Lazy import PILImage only when needed
67
- from .pil_image import PILImage # noqa: PLC0415
68
-
69
- # Handle different screenshot input types
70
- if isinstance(screenshot, (str, Path)):
71
- screenshot = PILImage.from_file(str(screenshot))
72
- elif isinstance(screenshot, bytes):
73
- screenshot = PILImage.from_bytes(screenshot)
74
-
75
- # Create a temporary task instance
76
- task = AsyncTask(api_key=api_key, base_url=base_url, temperature=temperature)
77
-
78
- try:
79
- # Initialize task and perform single step
80
- await task.init_task(task_description)
81
- result = await task.step(screenshot, instruction=instruction)
82
- return result
83
- finally:
84
- # Clean up resources
85
- await task.close()
oagi/single_step.py DELETED
@@ -1,87 +0,0 @@
1
- # -----------------------------------------------------------------------------
2
- # Copyright (c) OpenAGI Foundation
3
- # All rights reserved.
4
- #
5
- # This file is part of the official API project.
6
- # Licensed under the MIT License.
7
- # -----------------------------------------------------------------------------
8
-
9
- from pathlib import Path
10
-
11
- from .task import Task
12
- from .types import Image, Step
13
-
14
-
15
- def single_step(
16
- task_description: str,
17
- screenshot: str | bytes | Path | Image,
18
- instruction: str | None = None,
19
- api_key: str | None = None,
20
- base_url: str | None = None,
21
- temperature: float | None = None,
22
- ) -> Step:
23
- """
24
- Perform a single-step inference without maintaining task state.
25
-
26
- This is useful for one-off analyses where you don't need to maintain
27
- a conversation or task context across multiple steps.
28
-
29
- Args:
30
- task_description: Description of the task to perform
31
- screenshot: Screenshot as Image, bytes, or file path
32
- instruction: Optional additional instruction for the task
33
- api_key: OAGI API key (uses environment variable if not provided)
34
- base_url: OAGI base URL (uses environment variable if not provided)
35
- temperature: Sampling temperature (0.0-2.0) for LLM inference
36
-
37
- Returns:
38
- Step: Object containing reasoning, actions, and completion status
39
-
40
- Example:
41
- >>> # Using with bytes
42
- >>> with open("screenshot.png", "rb") as f:
43
- ... image_bytes = f.read()
44
- >>> step = single_step(
45
- ... task_description="Click the submit button",
46
- ... screenshot=image_bytes
47
- ... )
48
-
49
- >>> # Using with file path
50
- >>> step = single_step(
51
- ... task_description="Fill in the form",
52
- ... screenshot=Path("screenshot.png"),
53
- ... instruction="Use test@example.com for email"
54
- ... )
55
-
56
- >>> # Using with Image object
57
- >>> from oagi.types import Image
58
- >>> image = Image(...)
59
- >>> step = single_step(
60
- ... task_description="Navigate to settings",
61
- ... screenshot=image
62
- ... )
63
- """
64
- # Lazy import PILImage only when needed
65
- from .pil_image import PILImage # noqa: PLC0415
66
-
67
- # Convert file paths to bytes using PILImage
68
- if isinstance(screenshot, (str, Path)):
69
- path = Path(screenshot) if isinstance(screenshot, str) else screenshot
70
- if path.exists():
71
- pil_image = PILImage.from_file(str(path))
72
- screenshot_bytes = pil_image.read()
73
- else:
74
- raise FileNotFoundError(f"Screenshot file not found: {path}")
75
- elif isinstance(screenshot, bytes):
76
- screenshot_bytes = screenshot
77
- elif isinstance(screenshot, Image):
78
- screenshot_bytes = screenshot.read()
79
- else:
80
- raise ValueError(
81
- f"screenshot must be Image, bytes, str, or Path, got {type(screenshot)}"
82
- )
83
-
84
- # Use Task to perform single step
85
- with Task(api_key=api_key, base_url=base_url, temperature=temperature) as task:
86
- task.init_task(task_description)
87
- return task.step(screenshot_bytes, instruction=instruction)