oagi-core 0.9.0__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 +108 -0
- oagi/agent/__init__.py +31 -0
- oagi/agent/default.py +75 -0
- oagi/agent/factories.py +50 -0
- oagi/agent/protocol.py +55 -0
- oagi/agent/registry.py +155 -0
- oagi/agent/tasker/__init__.py +35 -0
- oagi/agent/tasker/memory.py +184 -0
- oagi/agent/tasker/models.py +83 -0
- oagi/agent/tasker/planner.py +385 -0
- oagi/agent/tasker/taskee_agent.py +395 -0
- oagi/agent/tasker/tasker_agent.py +323 -0
- oagi/async_pyautogui_action_handler.py +44 -0
- oagi/async_screenshot_maker.py +47 -0
- oagi/async_single_step.py +85 -0
- oagi/cli/__init__.py +11 -0
- oagi/cli/agent.py +125 -0
- oagi/cli/main.py +77 -0
- oagi/cli/server.py +94 -0
- oagi/cli/utils.py +82 -0
- oagi/client/__init__.py +12 -0
- oagi/client/async_.py +293 -0
- oagi/client/base.py +465 -0
- oagi/client/sync.py +296 -0
- oagi/exceptions.py +118 -0
- oagi/logging.py +47 -0
- oagi/pil_image.py +102 -0
- oagi/pyautogui_action_handler.py +268 -0
- oagi/screenshot_maker.py +41 -0
- oagi/server/__init__.py +13 -0
- oagi/server/agent_wrappers.py +98 -0
- oagi/server/config.py +46 -0
- oagi/server/main.py +157 -0
- oagi/server/models.py +98 -0
- oagi/server/session_store.py +116 -0
- oagi/server/socketio_server.py +405 -0
- oagi/single_step.py +87 -0
- oagi/task/__init__.py +14 -0
- oagi/task/async_.py +97 -0
- oagi/task/async_short.py +64 -0
- oagi/task/base.py +121 -0
- oagi/task/short.py +64 -0
- oagi/task/sync.py +97 -0
- oagi/types/__init__.py +28 -0
- oagi/types/action_handler.py +30 -0
- oagi/types/async_action_handler.py +30 -0
- oagi/types/async_image_provider.py +37 -0
- oagi/types/image.py +17 -0
- oagi/types/image_provider.py +34 -0
- oagi/types/models/__init__.py +32 -0
- oagi/types/models/action.py +33 -0
- oagi/types/models/client.py +64 -0
- oagi/types/models/image_config.py +47 -0
- oagi/types/models/step.py +17 -0
- oagi/types/url_image.py +47 -0
- oagi_core-0.9.0.dist-info/METADATA +257 -0
- oagi_core-0.9.0.dist-info/RECORD +60 -0
- oagi_core-0.9.0.dist-info/WHEEL +4 -0
- oagi_core-0.9.0.dist-info/entry_points.txt +2 -0
- oagi_core-0.9.0.dist-info/licenses/LICENSE +21 -0
oagi/task/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
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 .async_ import AsyncTask
|
|
10
|
+
from .async_short import AsyncShortTask
|
|
11
|
+
from .short import ShortTask
|
|
12
|
+
from .sync import Task
|
|
13
|
+
|
|
14
|
+
__all__ = ["Task", "AsyncTask", "ShortTask", "AsyncShortTask"]
|
oagi/task/async_.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
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 ..client import AsyncClient
|
|
10
|
+
from ..logging import get_logger
|
|
11
|
+
from ..types import Image, Step
|
|
12
|
+
from .base import BaseTask
|
|
13
|
+
|
|
14
|
+
logger = get_logger("async_task")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AsyncTask(BaseTask):
|
|
18
|
+
"""Async base class for task automation with the OAGI API."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
api_key: str | None = None,
|
|
23
|
+
base_url: str | None = None,
|
|
24
|
+
model: str = "vision-model-v1",
|
|
25
|
+
temperature: float | None = None,
|
|
26
|
+
):
|
|
27
|
+
super().__init__(api_key, base_url, model, temperature)
|
|
28
|
+
self.client = AsyncClient(base_url=base_url, api_key=api_key)
|
|
29
|
+
self.api_key = self.client.api_key
|
|
30
|
+
self.base_url = self.client.base_url
|
|
31
|
+
|
|
32
|
+
async def init_task(
|
|
33
|
+
self,
|
|
34
|
+
task_desc: str,
|
|
35
|
+
max_steps: int = 5,
|
|
36
|
+
):
|
|
37
|
+
"""Initialize a new task with the given description.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
task_desc: Task description
|
|
41
|
+
max_steps: Maximum number of steps (for logging)
|
|
42
|
+
"""
|
|
43
|
+
self._prepare_init_task(task_desc, max_steps)
|
|
44
|
+
|
|
45
|
+
async def step(
|
|
46
|
+
self,
|
|
47
|
+
screenshot: Image | bytes,
|
|
48
|
+
instruction: str | None = None,
|
|
49
|
+
temperature: float | None = None,
|
|
50
|
+
) -> Step:
|
|
51
|
+
"""Send screenshot to the server and get the next actions.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
screenshot: Screenshot as Image object or raw bytes
|
|
55
|
+
instruction: Optional additional instruction for this step
|
|
56
|
+
temperature: Sampling temperature for this step (overrides task default if provided)
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Step: The actions and reasoning for this step
|
|
60
|
+
"""
|
|
61
|
+
self._validate_step_preconditions()
|
|
62
|
+
self._log_step_execution(prefix="async ")
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Use provided temperature or fall back to task default
|
|
66
|
+
temp = self._get_temperature(temperature)
|
|
67
|
+
|
|
68
|
+
# Prepare screenshot kwargs (handles URLImage vs bytes/Image)
|
|
69
|
+
screenshot_kwargs = self._prepare_screenshot_kwargs(screenshot)
|
|
70
|
+
|
|
71
|
+
# Call API with dynamically determined screenshot argument
|
|
72
|
+
response = await self.client.create_message(
|
|
73
|
+
model=self.model,
|
|
74
|
+
task_description=self.task_description,
|
|
75
|
+
task_id=self.task_id,
|
|
76
|
+
instruction=instruction,
|
|
77
|
+
messages_history=self.message_history,
|
|
78
|
+
temperature=temp,
|
|
79
|
+
**screenshot_kwargs,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Convert API response to Step (also updates message_history)
|
|
83
|
+
return self._build_step_response(response, prefix="Async ")
|
|
84
|
+
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.error(f"Error during async step execution: {e}")
|
|
87
|
+
raise
|
|
88
|
+
|
|
89
|
+
async def close(self):
|
|
90
|
+
"""Close the underlying HTTP client to free resources."""
|
|
91
|
+
await self.client.close()
|
|
92
|
+
|
|
93
|
+
async def __aenter__(self):
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
97
|
+
await self.close()
|
oagi/task/async_short.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
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 ..logging import get_logger
|
|
10
|
+
from ..types import AsyncActionHandler, AsyncImageProvider
|
|
11
|
+
from .async_ import AsyncTask
|
|
12
|
+
from .base import BaseAutoMode
|
|
13
|
+
|
|
14
|
+
logger = get_logger("async_short_task")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AsyncShortTask(AsyncTask, BaseAutoMode):
|
|
18
|
+
"""Async task implementation with automatic mode for short-duration tasks."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
api_key: str | None = None,
|
|
23
|
+
base_url: str | None = None,
|
|
24
|
+
model: str = "vision-model-v1",
|
|
25
|
+
temperature: float | None = None,
|
|
26
|
+
):
|
|
27
|
+
super().__init__(
|
|
28
|
+
api_key=api_key, base_url=base_url, model=model, temperature=temperature
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
async def auto_mode(
|
|
32
|
+
self,
|
|
33
|
+
task_desc: str,
|
|
34
|
+
max_steps: int = 5,
|
|
35
|
+
executor: AsyncActionHandler = None,
|
|
36
|
+
image_provider: AsyncImageProvider = None,
|
|
37
|
+
temperature: float | None = None,
|
|
38
|
+
) -> bool:
|
|
39
|
+
"""Run the task in automatic mode with the provided executor and image provider.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
task_desc: Task description
|
|
43
|
+
max_steps: Maximum number of steps
|
|
44
|
+
executor: Async handler to execute actions
|
|
45
|
+
image_provider: Async provider for screenshots
|
|
46
|
+
temperature: Sampling temperature for all steps (overrides task default if provided)
|
|
47
|
+
"""
|
|
48
|
+
self._log_auto_mode_start(task_desc, max_steps, prefix="async ")
|
|
49
|
+
|
|
50
|
+
await self.init_task(task_desc, max_steps=max_steps)
|
|
51
|
+
|
|
52
|
+
for i in range(max_steps):
|
|
53
|
+
self._log_auto_mode_step(i + 1, max_steps, prefix="async ")
|
|
54
|
+
image = await image_provider()
|
|
55
|
+
step = await self.step(image, temperature=temperature)
|
|
56
|
+
if executor:
|
|
57
|
+
self._log_auto_mode_actions(len(step.actions), prefix="async ")
|
|
58
|
+
await executor(step.actions)
|
|
59
|
+
if step.stop:
|
|
60
|
+
self._log_auto_mode_completion(i + 1, prefix="async ")
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
self._log_auto_mode_max_steps(max_steps, prefix="async ")
|
|
64
|
+
return False
|
oagi/task/base.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
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 uuid import uuid4
|
|
10
|
+
|
|
11
|
+
from ..logging import get_logger
|
|
12
|
+
from ..types import Image, Step, URLImage
|
|
13
|
+
from ..types.models import LLMResponse
|
|
14
|
+
|
|
15
|
+
logger = get_logger("task.base")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseTask:
|
|
19
|
+
"""Base class with shared task management logic for sync/async tasks."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
api_key: str | None,
|
|
24
|
+
base_url: str | None,
|
|
25
|
+
model: str,
|
|
26
|
+
temperature: float | None,
|
|
27
|
+
):
|
|
28
|
+
self.task_id: str = uuid4().hex # Client-side generated UUID
|
|
29
|
+
self.task_description: str | None = None
|
|
30
|
+
self.model = model
|
|
31
|
+
self.temperature = temperature
|
|
32
|
+
self.message_history: list = [] # OpenAI-compatible message history
|
|
33
|
+
# Client will be set by subclasses
|
|
34
|
+
self.api_key: str | None = None
|
|
35
|
+
self.base_url: str | None = None
|
|
36
|
+
|
|
37
|
+
def _prepare_init_task(
|
|
38
|
+
self,
|
|
39
|
+
task_desc: str,
|
|
40
|
+
max_steps: int,
|
|
41
|
+
):
|
|
42
|
+
"""Prepare task initialization (v2 API does not call server for init).
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
task_desc: Task description
|
|
46
|
+
max_steps: Maximum number of steps
|
|
47
|
+
"""
|
|
48
|
+
self.task_description = task_desc
|
|
49
|
+
logger.info(f"Task initialized: '{task_desc}' (max_steps: {max_steps})")
|
|
50
|
+
|
|
51
|
+
def _validate_step_preconditions(self):
|
|
52
|
+
if not self.task_description:
|
|
53
|
+
raise ValueError("Task description must be set. Call init_task() first.")
|
|
54
|
+
|
|
55
|
+
def _prepare_screenshot(self, screenshot: Image | bytes) -> bytes:
|
|
56
|
+
if isinstance(screenshot, Image):
|
|
57
|
+
return screenshot.read()
|
|
58
|
+
return screenshot
|
|
59
|
+
|
|
60
|
+
def _get_temperature(self, temperature: float | None) -> float | None:
|
|
61
|
+
return temperature if temperature is not None else self.temperature
|
|
62
|
+
|
|
63
|
+
def _prepare_screenshot_kwargs(self, screenshot: Image | bytes) -> dict:
|
|
64
|
+
if isinstance(screenshot, URLImage):
|
|
65
|
+
return {"screenshot_url": screenshot.get_url()}
|
|
66
|
+
return {"screenshot": self._prepare_screenshot(screenshot)}
|
|
67
|
+
|
|
68
|
+
def _handle_response_message_history(self, response: LLMResponse):
|
|
69
|
+
if response.raw_output:
|
|
70
|
+
self.message_history.append(
|
|
71
|
+
{
|
|
72
|
+
"role": "assistant",
|
|
73
|
+
"content": [{"type": "text", "text": response.raw_output}],
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def _build_step_response(self, response: LLMResponse, prefix: str = "") -> Step:
|
|
78
|
+
# Update message history with assistant response
|
|
79
|
+
self._handle_response_message_history(response)
|
|
80
|
+
|
|
81
|
+
result = Step(
|
|
82
|
+
reason=response.reason,
|
|
83
|
+
actions=response.actions,
|
|
84
|
+
stop=response.is_complete,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if response.is_complete:
|
|
88
|
+
logger.info(f"{prefix}Task completed.")
|
|
89
|
+
else:
|
|
90
|
+
logger.debug(f"{prefix}Step completed with {len(response.actions)} actions")
|
|
91
|
+
|
|
92
|
+
return result
|
|
93
|
+
|
|
94
|
+
def _log_step_execution(self, prefix: str = ""):
|
|
95
|
+
logger.debug(f"Executing {prefix}step for task: '{self.task_description}'")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class BaseAutoMode:
|
|
99
|
+
"""Base class with shared auto_mode logic for ShortTask implementations."""
|
|
100
|
+
|
|
101
|
+
def _log_auto_mode_start(self, task_desc: str, max_steps: int, prefix: str = ""):
|
|
102
|
+
logger.info(
|
|
103
|
+
f"Starting {prefix}auto mode for task: '{task_desc}' (max_steps: {max_steps})"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def _log_auto_mode_step(self, step_num: int, max_steps: int, prefix: str = ""):
|
|
107
|
+
logger.debug(f"{prefix.capitalize()}auto mode step {step_num}/{max_steps}")
|
|
108
|
+
|
|
109
|
+
def _log_auto_mode_actions(self, action_count: int, prefix: str = ""):
|
|
110
|
+
verb = "asynchronously" if "async" in prefix else ""
|
|
111
|
+
logger.debug(f"Executing {action_count} actions {verb}".strip())
|
|
112
|
+
|
|
113
|
+
def _log_auto_mode_completion(self, steps: int, prefix: str = ""):
|
|
114
|
+
logger.info(
|
|
115
|
+
f"{prefix.capitalize()}auto mode completed successfully after {steps} steps"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def _log_auto_mode_max_steps(self, max_steps: int, prefix: str = ""):
|
|
119
|
+
logger.warning(
|
|
120
|
+
f"{prefix.capitalize()}auto mode reached max steps ({max_steps}) without completion"
|
|
121
|
+
)
|
oagi/task/short.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
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 ..logging import get_logger
|
|
10
|
+
from ..types import ActionHandler, ImageProvider
|
|
11
|
+
from .base import BaseAutoMode
|
|
12
|
+
from .sync import Task
|
|
13
|
+
|
|
14
|
+
logger = get_logger("short_task")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ShortTask(Task, BaseAutoMode):
|
|
18
|
+
"""Task implementation with automatic mode for short-duration tasks."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
api_key: str | None = None,
|
|
23
|
+
base_url: str | None = None,
|
|
24
|
+
model: str = "vision-model-v1",
|
|
25
|
+
temperature: float | None = None,
|
|
26
|
+
):
|
|
27
|
+
super().__init__(
|
|
28
|
+
api_key=api_key, base_url=base_url, model=model, temperature=temperature
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def auto_mode(
|
|
32
|
+
self,
|
|
33
|
+
task_desc: str,
|
|
34
|
+
max_steps: int = 5,
|
|
35
|
+
executor: ActionHandler = None,
|
|
36
|
+
image_provider: ImageProvider = None,
|
|
37
|
+
temperature: float | None = None,
|
|
38
|
+
) -> bool:
|
|
39
|
+
"""Run the task in automatic mode with the provided executor and image provider.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
task_desc: Task description
|
|
43
|
+
max_steps: Maximum number of steps
|
|
44
|
+
executor: Handler to execute actions
|
|
45
|
+
image_provider: Provider for screenshots
|
|
46
|
+
temperature: Sampling temperature for all steps (overrides task default if provided)
|
|
47
|
+
"""
|
|
48
|
+
self._log_auto_mode_start(task_desc, max_steps)
|
|
49
|
+
|
|
50
|
+
self.init_task(task_desc, max_steps=max_steps)
|
|
51
|
+
|
|
52
|
+
for i in range(max_steps):
|
|
53
|
+
self._log_auto_mode_step(i + 1, max_steps)
|
|
54
|
+
image = image_provider()
|
|
55
|
+
step = self.step(image, temperature=temperature)
|
|
56
|
+
if executor:
|
|
57
|
+
self._log_auto_mode_actions(len(step.actions))
|
|
58
|
+
executor(step.actions)
|
|
59
|
+
if step.stop:
|
|
60
|
+
self._log_auto_mode_completion(i + 1)
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
self._log_auto_mode_max_steps(max_steps)
|
|
64
|
+
return False
|
oagi/task/sync.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
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 ..client import SyncClient
|
|
10
|
+
from ..logging import get_logger
|
|
11
|
+
from ..types import Image, Step
|
|
12
|
+
from .base import BaseTask
|
|
13
|
+
|
|
14
|
+
logger = get_logger("task")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Task(BaseTask):
|
|
18
|
+
"""Base class for task automation with the OAGI API."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
api_key: str | None = None,
|
|
23
|
+
base_url: str | None = None,
|
|
24
|
+
model: str = "vision-model-v1",
|
|
25
|
+
temperature: float | None = None,
|
|
26
|
+
):
|
|
27
|
+
super().__init__(api_key, base_url, model, temperature)
|
|
28
|
+
self.client = SyncClient(base_url=base_url, api_key=api_key)
|
|
29
|
+
self.api_key = self.client.api_key
|
|
30
|
+
self.base_url = self.client.base_url
|
|
31
|
+
|
|
32
|
+
def init_task(
|
|
33
|
+
self,
|
|
34
|
+
task_desc: str,
|
|
35
|
+
max_steps: int = 5,
|
|
36
|
+
):
|
|
37
|
+
"""Initialize a new task with the given description.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
task_desc: Task description
|
|
41
|
+
max_steps: Maximum number of steps (for logging)
|
|
42
|
+
"""
|
|
43
|
+
self._prepare_init_task(task_desc, max_steps)
|
|
44
|
+
|
|
45
|
+
def step(
|
|
46
|
+
self,
|
|
47
|
+
screenshot: Image | bytes,
|
|
48
|
+
instruction: str | None = None,
|
|
49
|
+
temperature: float | None = None,
|
|
50
|
+
) -> Step:
|
|
51
|
+
"""Send screenshot to the server and get the next actions.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
screenshot: Screenshot as Image object or raw bytes
|
|
55
|
+
instruction: Optional additional instruction for this step
|
|
56
|
+
temperature: Sampling temperature for this step (overrides task default if provided)
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Step: The actions and reasoning for this step
|
|
60
|
+
"""
|
|
61
|
+
self._validate_step_preconditions()
|
|
62
|
+
self._log_step_execution()
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
# Use provided temperature or fall back to task default
|
|
66
|
+
temp = self._get_temperature(temperature)
|
|
67
|
+
|
|
68
|
+
# Prepare screenshot kwargs (handles URLImage vs bytes/Image)
|
|
69
|
+
screenshot_kwargs = self._prepare_screenshot_kwargs(screenshot)
|
|
70
|
+
|
|
71
|
+
# Call API with dynamically determined screenshot argument
|
|
72
|
+
response = self.client.create_message(
|
|
73
|
+
model=self.model,
|
|
74
|
+
task_description=self.task_description,
|
|
75
|
+
task_id=self.task_id,
|
|
76
|
+
instruction=instruction,
|
|
77
|
+
messages_history=self.message_history,
|
|
78
|
+
temperature=temp,
|
|
79
|
+
**screenshot_kwargs,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Convert API response to Step (also updates message_history)
|
|
83
|
+
return self._build_step_response(response)
|
|
84
|
+
|
|
85
|
+
except Exception as e:
|
|
86
|
+
logger.error(f"Error during step execution: {e}")
|
|
87
|
+
raise
|
|
88
|
+
|
|
89
|
+
def close(self):
|
|
90
|
+
"""Close the underlying HTTP client to free resources."""
|
|
91
|
+
self.client.close()
|
|
92
|
+
|
|
93
|
+
def __enter__(self):
|
|
94
|
+
return self
|
|
95
|
+
|
|
96
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
97
|
+
self.close()
|
oagi/types/__init__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
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 .action_handler import ActionHandler
|
|
10
|
+
from .async_action_handler import AsyncActionHandler
|
|
11
|
+
from .async_image_provider import AsyncImageProvider
|
|
12
|
+
from .image import Image
|
|
13
|
+
from .image_provider import ImageProvider
|
|
14
|
+
from .models import Action, ActionType, ImageConfig, Step
|
|
15
|
+
from .url_image import URLImage
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"Action",
|
|
19
|
+
"ActionType",
|
|
20
|
+
"Image",
|
|
21
|
+
"ImageConfig",
|
|
22
|
+
"Step",
|
|
23
|
+
"ActionHandler",
|
|
24
|
+
"AsyncActionHandler",
|
|
25
|
+
"ImageProvider",
|
|
26
|
+
"AsyncImageProvider",
|
|
27
|
+
"URLImage",
|
|
28
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
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 ActionHandler(Protocol):
|
|
15
|
+
def __call__(self, actions: list[Action]) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Executes a list of actions.
|
|
18
|
+
|
|
19
|
+
This method takes a list of `Action` objects and executes them. It is used
|
|
20
|
+
to perform operations represented by the `Action` instances. This method
|
|
21
|
+
does not return any value and modifies the system based on the input actions.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
actions (list[Action]): A list of `Action` objects to be executed. Each
|
|
25
|
+
`Action` must encapsulate the logic that is intended to be applied
|
|
26
|
+
during the call.
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
RuntimeError: If an error occurs during the execution of the actions.
|
|
30
|
+
"""
|
|
@@ -0,0 +1,30 @@
|
|
|
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 AsyncActionHandler(Protocol):
|
|
15
|
+
async def __call__(self, actions: list[Action]) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Asynchronously executes a list of actions.
|
|
18
|
+
|
|
19
|
+
This method takes a list of `Action` objects and executes them asynchronously.
|
|
20
|
+
It is used to perform operations represented by the `Action` instances. This
|
|
21
|
+
method does not return any value and modifies the system based on the input actions.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
actions (list[Action]): A list of `Action` objects to be executed. Each
|
|
25
|
+
`Action` must encapsulate the logic that is intended to be applied
|
|
26
|
+
during the call.
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
RuntimeError: If an error occurs during the execution of the actions.
|
|
30
|
+
"""
|
|
@@ -0,0 +1,37 @@
|
|
|
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 .image import Image
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AsyncImageProvider(Protocol):
|
|
15
|
+
async def __call__(self) -> Image:
|
|
16
|
+
"""
|
|
17
|
+
Asynchronously provides an image.
|
|
18
|
+
|
|
19
|
+
This method is responsible for asynchronously capturing, generating, or retrieving
|
|
20
|
+
an image that can be used for task execution or analysis. The method should return
|
|
21
|
+
an object that implements the Image protocol.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Image: An object implementing the Image protocol that represents
|
|
25
|
+
the captured or generated image.
|
|
26
|
+
|
|
27
|
+
Raises:
|
|
28
|
+
RuntimeError: If an error occurs during image capture or generation.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
async def last_image(self) -> Image:
|
|
32
|
+
"""
|
|
33
|
+
Asynchronously returns the last captured image.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Image: The last captured image.
|
|
37
|
+
"""
|
oagi/types/image.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
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, runtime_checkable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class Image(Protocol):
|
|
14
|
+
"""Protocol for image objects that can be read as bytes."""
|
|
15
|
+
|
|
16
|
+
def read(self) -> bytes:
|
|
17
|
+
"""Read the image data as bytes."""
|
|
@@ -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 .image import Image
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ImageProvider(Protocol):
|
|
15
|
+
def __call__(self) -> Image:
|
|
16
|
+
"""
|
|
17
|
+
Represents the functionality to invoke the callable object and produce an Image
|
|
18
|
+
result. Typically used to process or generate images using the defined logic
|
|
19
|
+
within the __call__ method.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Image: The resulting image output from the callable logic.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def last_image(self) -> Image:
|
|
26
|
+
"""
|
|
27
|
+
Returns the last captured image.
|
|
28
|
+
|
|
29
|
+
This method retrieves the most recent image that was captured and stored
|
|
30
|
+
in memory. If there are no images available, the method may return None.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Image: The last captured image, or None if no images are available.
|
|
34
|
+
"""
|
|
@@ -0,0 +1,32 @@
|
|
|
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 .action import Action, ActionType
|
|
10
|
+
from .client import (
|
|
11
|
+
ErrorDetail,
|
|
12
|
+
ErrorResponse,
|
|
13
|
+
GenerateResponse,
|
|
14
|
+
LLMResponse,
|
|
15
|
+
UploadFileResponse,
|
|
16
|
+
Usage,
|
|
17
|
+
)
|
|
18
|
+
from .image_config import ImageConfig
|
|
19
|
+
from .step import Step
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"Action",
|
|
23
|
+
"ActionType",
|
|
24
|
+
"ErrorDetail",
|
|
25
|
+
"ErrorResponse",
|
|
26
|
+
"GenerateResponse",
|
|
27
|
+
"ImageConfig",
|
|
28
|
+
"LLMResponse",
|
|
29
|
+
"Step",
|
|
30
|
+
"UploadFileResponse",
|
|
31
|
+
"Usage",
|
|
32
|
+
]
|