oagi-core 0.10.0__tar.gz → 0.10.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.
- {oagi_core-0.10.0 → oagi_core-0.10.1}/PKG-INFO +2 -1
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/tasker_agent_example.py +0 -6
- {oagi_core-0.10.0 → oagi_core-0.10.1}/metapackage/pyproject.toml +2 -2
- {oagi_core-0.10.0 → oagi_core-0.10.1}/metapackage/uv.lock +5 -5
- {oagi_core-0.10.0 → oagi_core-0.10.1}/pyproject.toml +2 -1
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/__init__.py +0 -2
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/memory.py +3 -27
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/models.py +0 -7
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/planner.py +2 -11
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/tasker_agent.py +3 -17
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/agent.py +99 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/async_.py +0 -3
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/base.py +0 -4
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/sync.py +0 -3
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/pyautogui_action_handler.py +8 -2
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/client.py +7 -3
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_planner.py +5 -6
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_planner_memory.py +0 -13
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_taskee_agent.py +5 -5
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_tasker_agent.py +10 -23
- {oagi_core-0.10.0 → oagi_core-0.10.1}/uv.lock +71 -28
- {oagi_core-0.10.0 → oagi_core-0.10.1}/.github/workflows/ci.yml +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/.github/workflows/release.yml +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/.gitignore +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/.python-version +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/CONTRIBUTING.md +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/LICENSE +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/Makefile +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/README.md +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/async_google_weather.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/execute_task_auto.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/execute_task_manual.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/google_weather.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/screenshot_with_config.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/default.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/factories.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/agent_observer.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/events.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/exporters.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/protocol.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/protocol.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/registry.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/taskee_agent.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/display.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/main.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/server.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/tracking.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/utils.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/exceptions.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/_macos.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/async_pyautogui_action_handler.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/async_screenshot_maker.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/pil_image.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/screenshot_maker.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/logging.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/agent_wrappers.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/config.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/main.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/models.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/session_store.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/socketio_server.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/async_.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/async_short.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/base.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/short.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/sync.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/action_handler.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/async_action_handler.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/async_image_provider.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/image.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/image_provider.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/action.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/image_config.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/step.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/step_observer.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/url.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/conftest.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_actor.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent/test_agent_wrappers.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent/test_default_agent.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent_registry.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_actor.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_client.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_handlers.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_cli.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_logging.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_mac_double_click.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_observer.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_pil_image.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_pyautogui_action_handler.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_screenshot_maker.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/__init__.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_config.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_session_store.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_socketio_integration.py +0 -0
- {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_sync_client.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: oagi-core
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.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>
|
|
@@ -32,6 +32,7 @@ Requires-Dist: rich>=13.0.0
|
|
|
32
32
|
Provides-Extra: desktop
|
|
33
33
|
Requires-Dist: pillow>=11.3.0; extra == 'desktop'
|
|
34
34
|
Requires-Dist: pyautogui>=0.9.54; extra == 'desktop'
|
|
35
|
+
Requires-Dist: pyobjc-framework-applicationservices>=9.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
35
36
|
Requires-Dist: pyobjc-framework-quartz>=9.0; (sys_platform == 'darwin') and extra == 'desktop'
|
|
36
37
|
Provides-Extra: server
|
|
37
38
|
Requires-Dist: fastapi[standard]>=0.115.0; extra == 'server'
|
|
@@ -42,16 +42,10 @@ async def main():
|
|
|
42
42
|
"Click on the official Python.org website link",
|
|
43
43
|
]
|
|
44
44
|
|
|
45
|
-
# Define deliverables to achieve
|
|
46
|
-
deliverables = [
|
|
47
|
-
"Python.org website is opened",
|
|
48
|
-
]
|
|
49
|
-
|
|
50
45
|
# Set the task
|
|
51
46
|
tasker.set_task(
|
|
52
47
|
task=task_description,
|
|
53
48
|
todos=todos,
|
|
54
|
-
deliverables=deliverables,
|
|
55
49
|
)
|
|
56
50
|
|
|
57
51
|
image_provider = AsyncScreenshotMaker()
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oagi"
|
|
7
|
-
version = "0.10.
|
|
7
|
+
version = "0.10.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.10.
|
|
19
|
+
"oagi-core[desktop,server]==0.10.1",
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
[project.urls]
|
|
@@ -397,27 +397,27 @@ sdist = { url = "https://files.pythonhosted.org/packages/28/fa/b2ba8229b9381e8f6
|
|
|
397
397
|
|
|
398
398
|
[[package]]
|
|
399
399
|
name = "oagi"
|
|
400
|
-
version = "0.10.
|
|
400
|
+
version = "0.10.1"
|
|
401
401
|
source = { editable = "." }
|
|
402
402
|
dependencies = [
|
|
403
403
|
{ name = "oagi-core", extra = ["desktop", "server"] },
|
|
404
404
|
]
|
|
405
405
|
|
|
406
406
|
[package.metadata]
|
|
407
|
-
requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.
|
|
407
|
+
requires-dist = [{ name = "oagi-core", extras = ["desktop", "server"], specifier = "==0.10.0" }]
|
|
408
408
|
|
|
409
409
|
[[package]]
|
|
410
410
|
name = "oagi-core"
|
|
411
|
-
version = "0.
|
|
411
|
+
version = "0.10.0"
|
|
412
412
|
source = { registry = "https://pypi.org/simple" }
|
|
413
413
|
dependencies = [
|
|
414
414
|
{ name = "httpx" },
|
|
415
415
|
{ name = "pydantic" },
|
|
416
416
|
{ name = "rich" },
|
|
417
417
|
]
|
|
418
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
418
|
+
sdist = { url = "https://files.pythonhosted.org/packages/2d/3f/6fa48d2d207051d5f3a8eedf8f7d9cd97f7463746f6578b6655511a4cf47/oagi_core-0.10.0.tar.gz", hash = "sha256:d50c6dac28eb4d395e6910bd24cf412845ffbad25c1be7a2a6a04511691470e9", size = 259893, upload-time = "2025-11-24T04:15:08.503Z" }
|
|
419
419
|
wheels = [
|
|
420
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
420
|
+
{ url = "https://files.pythonhosted.org/packages/44/9f/582af4d42c1074fe647a3fdbdaddb0bd7b4402ac85e42ea9dcfdf7b52528/oagi_core-0.10.0-py3-none-any.whl", hash = "sha256:f7e19c744586dfb22cfcef0ddc031a457ad4605e6441198cdc6bc4f27bebbb1a", size = 83329, upload-time = "2025-11-24T04:15:07.201Z" },
|
|
421
421
|
]
|
|
422
422
|
|
|
423
423
|
[package.optional-dependencies]
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oagi-core"
|
|
7
|
-
version = "0.10.
|
|
7
|
+
version = "0.10.1"
|
|
8
8
|
description = "Official API of OpenAGI Foundation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -31,6 +31,7 @@ desktop = [
|
|
|
31
31
|
"pillow>=11.3.0",
|
|
32
32
|
"pyautogui>=0.9.54",
|
|
33
33
|
"pyobjc-framework-Quartz>=9.0; sys_platform == 'darwin'",
|
|
34
|
+
"pyobjc-framework-ApplicationServices>=9.0; sys_platform == 'darwin'",
|
|
34
35
|
]
|
|
35
36
|
server = [
|
|
36
37
|
"fastapi[standard]>=0.115.0",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
from .memory import PlannerMemory
|
|
10
10
|
from .models import (
|
|
11
11
|
Action,
|
|
12
|
-
Deliverable,
|
|
13
12
|
PlannerOutput,
|
|
14
13
|
ReflectionOutput,
|
|
15
14
|
Todo,
|
|
@@ -27,7 +26,6 @@ __all__ = [
|
|
|
27
26
|
"Planner",
|
|
28
27
|
"Todo",
|
|
29
28
|
"TodoStatus",
|
|
30
|
-
"Deliverable",
|
|
31
29
|
"Action",
|
|
32
30
|
"TodoHistory",
|
|
33
31
|
"PlannerOutput",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
|
-
from .models import Action,
|
|
11
|
+
from .models import Action, Todo, TodoHistory, TodoStatus
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class PlannerMemory:
|
|
@@ -16,7 +16,7 @@ class PlannerMemory:
|
|
|
16
16
|
|
|
17
17
|
This class manages the hierarchical task execution state for TaskerAgent.
|
|
18
18
|
It provides methods for:
|
|
19
|
-
- Task/todo
|
|
19
|
+
- Task/todo management
|
|
20
20
|
- Execution history tracking
|
|
21
21
|
- Memory state serialization
|
|
22
22
|
|
|
@@ -27,7 +27,6 @@ class PlannerMemory:
|
|
|
27
27
|
"""Initialize empty memory."""
|
|
28
28
|
self.task_description: str = ""
|
|
29
29
|
self.todos: list[Todo] = []
|
|
30
|
-
self.deliverables: list[Deliverable] = []
|
|
31
30
|
self.history: list[TodoHistory] = []
|
|
32
31
|
self.task_execution_summary: str = ""
|
|
33
32
|
self.todo_execution_summaries: dict[int, str] = {}
|
|
@@ -36,14 +35,12 @@ class PlannerMemory:
|
|
|
36
35
|
self,
|
|
37
36
|
task_description: str,
|
|
38
37
|
todos: list[str] | list[Todo],
|
|
39
|
-
deliverables: list[str] | list[Deliverable] | None = None,
|
|
40
38
|
) -> None:
|
|
41
|
-
"""Set the task
|
|
39
|
+
"""Set the task and todos.
|
|
42
40
|
|
|
43
41
|
Args:
|
|
44
42
|
task_description: Overall task description
|
|
45
43
|
todos: List of todo items (strings or Todo objects)
|
|
46
|
-
deliverables: Optional list of deliverables (strings or Deliverable objects)
|
|
47
44
|
"""
|
|
48
45
|
self.task_description = task_description
|
|
49
46
|
|
|
@@ -55,15 +52,6 @@ class PlannerMemory:
|
|
|
55
52
|
else:
|
|
56
53
|
self.todos.append(todo)
|
|
57
54
|
|
|
58
|
-
# Convert deliverables
|
|
59
|
-
self.deliverables = []
|
|
60
|
-
if deliverables:
|
|
61
|
-
for deliverable in deliverables:
|
|
62
|
-
if isinstance(deliverable, str):
|
|
63
|
-
self.deliverables.append(Deliverable(description=deliverable))
|
|
64
|
-
else:
|
|
65
|
-
self.deliverables.append(deliverable)
|
|
66
|
-
|
|
67
55
|
def get_current_todo(self) -> tuple[Todo | None, int]:
|
|
68
56
|
"""Get the next pending or in-progress todo.
|
|
69
57
|
|
|
@@ -133,10 +121,6 @@ class PlannerMemory:
|
|
|
133
121
|
{"index": i, "description": t.description, "status": t.status}
|
|
134
122
|
for i, t in enumerate(self.todos)
|
|
135
123
|
],
|
|
136
|
-
"deliverables": [
|
|
137
|
-
{"description": d.description, "achieved": d.achieved}
|
|
138
|
-
for d in self.deliverables
|
|
139
|
-
],
|
|
140
124
|
"history": [
|
|
141
125
|
{
|
|
142
126
|
"todo_index": h.todo_index,
|
|
@@ -174,11 +158,3 @@ class PlannerMemory:
|
|
|
174
158
|
description: Description of the new todo
|
|
175
159
|
"""
|
|
176
160
|
self.todos.append(Todo(description=description))
|
|
177
|
-
|
|
178
|
-
def append_deliverable(self, description: str) -> None:
|
|
179
|
-
"""Append a new deliverable to the list.
|
|
180
|
-
|
|
181
|
-
Args:
|
|
182
|
-
description: Description of the new deliverable
|
|
183
|
-
"""
|
|
184
|
-
self.deliverables.append(Deliverable(description=description))
|
|
@@ -28,13 +28,6 @@ class Todo(BaseModel):
|
|
|
28
28
|
status: TodoStatus = TodoStatus.PENDING
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class Deliverable(BaseModel):
|
|
32
|
-
"""A deliverable or goal to be achieved."""
|
|
33
|
-
|
|
34
|
-
description: str
|
|
35
|
-
achieved: bool = False
|
|
36
|
-
|
|
37
|
-
|
|
38
31
|
class Action(BaseModel):
|
|
39
32
|
"""An action taken during execution."""
|
|
40
33
|
|
|
@@ -62,7 +62,7 @@ class Planner:
|
|
|
62
62
|
memory: PlannerMemory | None,
|
|
63
63
|
context: dict[str, Any],
|
|
64
64
|
todo_index: int | None = None,
|
|
65
|
-
) -> tuple[str, list, list,
|
|
65
|
+
) -> tuple[str, list, list, str | None, str]:
|
|
66
66
|
"""Extract memory data for API calls.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
@@ -71,7 +71,7 @@ class Planner:
|
|
|
71
71
|
todo_index: Optional todo index for extracting overall_todo
|
|
72
72
|
|
|
73
73
|
Returns:
|
|
74
|
-
Tuple of (task_description, todos,
|
|
74
|
+
Tuple of (task_description, todos, history,
|
|
75
75
|
task_execution_summary, overall_todo)
|
|
76
76
|
"""
|
|
77
77
|
if memory and todo_index is not None:
|
|
@@ -86,7 +86,6 @@ class Planner:
|
|
|
86
86
|
}
|
|
87
87
|
for i, t in enumerate(memory.todos)
|
|
88
88
|
]
|
|
89
|
-
deliverables = [d.model_dump() for d in memory.deliverables]
|
|
90
89
|
history = [
|
|
91
90
|
{
|
|
92
91
|
"todo_index": h.todo_index,
|
|
@@ -103,7 +102,6 @@ class Planner:
|
|
|
103
102
|
# Fallback to basic context
|
|
104
103
|
task_description = context.get("task_description", "")
|
|
105
104
|
todos = context.get("todos", [])
|
|
106
|
-
deliverables = context.get("deliverables", [])
|
|
107
105
|
history = context.get("history", [])
|
|
108
106
|
task_execution_summary = None
|
|
109
107
|
overall_todo = context.get("current_todo", "")
|
|
@@ -111,7 +109,6 @@ class Planner:
|
|
|
111
109
|
return (
|
|
112
110
|
task_description,
|
|
113
111
|
todos,
|
|
114
|
-
deliverables,
|
|
115
112
|
history,
|
|
116
113
|
task_execution_summary,
|
|
117
114
|
overall_todo,
|
|
@@ -150,7 +147,6 @@ class Planner:
|
|
|
150
147
|
(
|
|
151
148
|
task_description,
|
|
152
149
|
todos,
|
|
153
|
-
deliverables,
|
|
154
150
|
history,
|
|
155
151
|
task_execution_summary,
|
|
156
152
|
_, # overall_todo not needed here, we use the `todo` parameter
|
|
@@ -162,7 +158,6 @@ class Planner:
|
|
|
162
158
|
overall_todo=todo,
|
|
163
159
|
task_description=task_description,
|
|
164
160
|
todos=todos,
|
|
165
|
-
deliverables=deliverables,
|
|
166
161
|
history=history,
|
|
167
162
|
current_todo_index=todo_index,
|
|
168
163
|
task_execution_summary=task_execution_summary,
|
|
@@ -209,7 +204,6 @@ class Planner:
|
|
|
209
204
|
(
|
|
210
205
|
task_description,
|
|
211
206
|
todos,
|
|
212
|
-
deliverables,
|
|
213
207
|
history,
|
|
214
208
|
task_execution_summary,
|
|
215
209
|
overall_todo,
|
|
@@ -245,7 +239,6 @@ class Planner:
|
|
|
245
239
|
overall_todo=overall_todo,
|
|
246
240
|
task_description=task_description,
|
|
247
241
|
todos=todos,
|
|
248
|
-
deliverables=deliverables,
|
|
249
242
|
history=history,
|
|
250
243
|
current_todo_index=todo_index,
|
|
251
244
|
task_execution_summary=task_execution_summary,
|
|
@@ -284,7 +277,6 @@ class Planner:
|
|
|
284
277
|
(
|
|
285
278
|
task_description,
|
|
286
279
|
todos,
|
|
287
|
-
deliverables,
|
|
288
280
|
history,
|
|
289
281
|
task_execution_summary,
|
|
290
282
|
overall_todo,
|
|
@@ -302,7 +294,6 @@ class Planner:
|
|
|
302
294
|
overall_todo=overall_todo,
|
|
303
295
|
task_description=task_description,
|
|
304
296
|
todos=todos,
|
|
305
|
-
deliverables=deliverables,
|
|
306
297
|
history=history,
|
|
307
298
|
current_todo_index=todo_index,
|
|
308
299
|
task_execution_summary=task_execution_summary,
|
|
@@ -73,20 +73,15 @@ class TaskerAgent(AsyncAgent):
|
|
|
73
73
|
self,
|
|
74
74
|
task: str,
|
|
75
75
|
todos: list[str],
|
|
76
|
-
deliverables: list[str] | None = None,
|
|
77
76
|
) -> None:
|
|
78
|
-
"""Set the task
|
|
77
|
+
"""Set the task and todos for the workflow.
|
|
79
78
|
|
|
80
79
|
Args:
|
|
81
80
|
task: Overall task description
|
|
82
81
|
todos: List of todo descriptions
|
|
83
|
-
deliverables: Optional list of deliverable descriptions
|
|
84
82
|
"""
|
|
85
|
-
self.memory.set_task(task, todos
|
|
86
|
-
logger.info(
|
|
87
|
-
f"Task set with {len(todos)} todos and "
|
|
88
|
-
f"{len(deliverables) if deliverables else 0} deliverables"
|
|
89
|
-
)
|
|
83
|
+
self.memory.set_task(task, todos)
|
|
84
|
+
logger.info(f"Task set with {len(todos)} todos")
|
|
90
85
|
|
|
91
86
|
async def execute(
|
|
92
87
|
self,
|
|
@@ -327,12 +322,3 @@ class TaskerAgent(AsyncAgent):
|
|
|
327
322
|
"""
|
|
328
323
|
self.memory.append_todo(description)
|
|
329
324
|
logger.info(f"Appended new todo: {description}")
|
|
330
|
-
|
|
331
|
-
def append_deliverable(self, description: str) -> None:
|
|
332
|
-
"""Dynamically append a new deliverable to the workflow.
|
|
333
|
-
|
|
334
|
-
Args:
|
|
335
|
-
description: Description of the new deliverable
|
|
336
|
-
"""
|
|
337
|
-
self.memory.append_deliverable(description)
|
|
338
|
-
logger.info(f"Appended new deliverable: {description}")
|
|
@@ -66,10 +66,106 @@ def add_agent_parser(subparsers: argparse._SubParsersAction) -> None:
|
|
|
66
66
|
help="Output file path for export (default: execution_report.[md|html|json])",
|
|
67
67
|
)
|
|
68
68
|
|
|
69
|
+
# agent permission command
|
|
70
|
+
agent_subparsers.add_parser(
|
|
71
|
+
"permission",
|
|
72
|
+
help="Check macOS permissions for screen recording and accessibility",
|
|
73
|
+
)
|
|
74
|
+
|
|
69
75
|
|
|
70
76
|
def handle_agent_command(args: argparse.Namespace) -> None:
|
|
71
77
|
if args.agent_command == "run":
|
|
72
78
|
run_agent(args)
|
|
79
|
+
elif args.agent_command == "permission":
|
|
80
|
+
check_permissions()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def check_permissions() -> None:
|
|
84
|
+
"""Check and request macOS permissions for screen recording and accessibility.
|
|
85
|
+
|
|
86
|
+
Guides the user through granting permissions one at a time.
|
|
87
|
+
"""
|
|
88
|
+
if sys.platform != "darwin":
|
|
89
|
+
print("Warning: Permission check is only applicable on macOS.")
|
|
90
|
+
print("On other platforms, no special permissions are required.")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
check_optional_dependency("Quartz", "Permission check", "desktop")
|
|
94
|
+
check_optional_dependency("ApplicationServices", "Permission check", "desktop")
|
|
95
|
+
|
|
96
|
+
import subprocess # noqa: PLC0415
|
|
97
|
+
|
|
98
|
+
from ApplicationServices import AXIsProcessTrusted # noqa: PLC0415
|
|
99
|
+
from Quartz import ( # noqa: PLC0415
|
|
100
|
+
CGPreflightScreenCaptureAccess,
|
|
101
|
+
CGRequestScreenCaptureAccess,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Check all permissions first to show status
|
|
105
|
+
screen_recording_granted = CGPreflightScreenCaptureAccess()
|
|
106
|
+
accessibility_granted = AXIsProcessTrusted()
|
|
107
|
+
|
|
108
|
+
print("Checking permissions...")
|
|
109
|
+
print(f" {'[OK]' if screen_recording_granted else '[MISSING]'} Screen Recording")
|
|
110
|
+
print(f" {'[OK]' if accessibility_granted else '[MISSING]'} Accessibility")
|
|
111
|
+
|
|
112
|
+
# Guide user through missing permissions one at a time
|
|
113
|
+
if not screen_recording_granted:
|
|
114
|
+
CGRequestScreenCaptureAccess()
|
|
115
|
+
subprocess.run(
|
|
116
|
+
[
|
|
117
|
+
"open",
|
|
118
|
+
"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture",
|
|
119
|
+
],
|
|
120
|
+
check=False,
|
|
121
|
+
)
|
|
122
|
+
print("\nPlease grant Screen Recording permission in System Preferences.")
|
|
123
|
+
print("After granting, run this command again to continue.")
|
|
124
|
+
print("Note: You may need to restart your terminal after granting permissions.")
|
|
125
|
+
sys.exit(1)
|
|
126
|
+
|
|
127
|
+
if not accessibility_granted:
|
|
128
|
+
subprocess.run(
|
|
129
|
+
[
|
|
130
|
+
"open",
|
|
131
|
+
"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility",
|
|
132
|
+
],
|
|
133
|
+
check=False,
|
|
134
|
+
)
|
|
135
|
+
print("\nPlease grant Accessibility permission in System Preferences.")
|
|
136
|
+
print("After granting, run this command again to continue.")
|
|
137
|
+
print("Note: You may need to restart your terminal after granting permissions.")
|
|
138
|
+
sys.exit(1)
|
|
139
|
+
|
|
140
|
+
print()
|
|
141
|
+
print("All permissions granted. You can run the agent.")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _warn_missing_permissions() -> None:
|
|
145
|
+
if sys.platform != "darwin":
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
if not check_optional_dependency(
|
|
149
|
+
"Quartz", "Permission check", "desktop", raise_error=False
|
|
150
|
+
):
|
|
151
|
+
return
|
|
152
|
+
if not check_optional_dependency(
|
|
153
|
+
"ApplicationServices", "Permission check", "desktop", raise_error=False
|
|
154
|
+
):
|
|
155
|
+
return
|
|
156
|
+
|
|
157
|
+
from ApplicationServices import AXIsProcessTrusted # noqa: PLC0415
|
|
158
|
+
from Quartz import CGPreflightScreenCaptureAccess # noqa: PLC0415
|
|
159
|
+
|
|
160
|
+
missing = []
|
|
161
|
+
if not CGPreflightScreenCaptureAccess():
|
|
162
|
+
missing.append("Screen Recording")
|
|
163
|
+
if not AXIsProcessTrusted():
|
|
164
|
+
missing.append("Accessibility")
|
|
165
|
+
|
|
166
|
+
if missing:
|
|
167
|
+
print(f"Warning: Missing macOS permissions: {', '.join(missing)}")
|
|
168
|
+
print("Run 'oagi agent permission' to configure permissions.\n")
|
|
73
169
|
|
|
74
170
|
|
|
75
171
|
def run_agent(args: argparse.Namespace) -> None:
|
|
@@ -77,6 +173,9 @@ def run_agent(args: argparse.Namespace) -> None:
|
|
|
77
173
|
check_optional_dependency("pyautogui", "Agent execution", "desktop")
|
|
78
174
|
check_optional_dependency("PIL", "Agent execution", "desktop")
|
|
79
175
|
|
|
176
|
+
# Warn about missing macOS permissions (non-blocking)
|
|
177
|
+
_warn_missing_permissions()
|
|
178
|
+
|
|
80
179
|
from oagi import AsyncPyautoguiActionHandler, AsyncScreenshotMaker # noqa: PLC0415
|
|
81
180
|
from oagi.agent import create_agent # noqa: PLC0415
|
|
82
181
|
|
|
@@ -223,7 +223,6 @@ class AsyncClient(BaseClient[httpx.AsyncClient]):
|
|
|
223
223
|
overall_todo: str,
|
|
224
224
|
task_description: str,
|
|
225
225
|
todos: list[dict],
|
|
226
|
-
deliverables: list[dict],
|
|
227
226
|
history: list[dict] | None = None,
|
|
228
227
|
current_todo_index: int | None = None,
|
|
229
228
|
task_execution_summary: str | None = None,
|
|
@@ -243,7 +242,6 @@ class AsyncClient(BaseClient[httpx.AsyncClient]):
|
|
|
243
242
|
overall_todo: Current todo description
|
|
244
243
|
task_description: Overall task description
|
|
245
244
|
todos: List of todo dicts with index, description, status, execution_summary
|
|
246
|
-
deliverables: List of deliverable dicts with description, achieved
|
|
247
245
|
history: List of history dicts with todo_index, todo_description, action_count, summary, completed
|
|
248
246
|
current_todo_index: Index of current todo being executed
|
|
249
247
|
task_execution_summary: Summary of overall task execution
|
|
@@ -269,7 +267,6 @@ class AsyncClient(BaseClient[httpx.AsyncClient]):
|
|
|
269
267
|
overall_todo=overall_todo,
|
|
270
268
|
task_description=task_description,
|
|
271
269
|
todos=todos,
|
|
272
|
-
deliverables=deliverables,
|
|
273
270
|
history=history,
|
|
274
271
|
current_todo_index=current_todo_index,
|
|
275
272
|
task_execution_summary=task_execution_summary,
|
|
@@ -348,7 +348,6 @@ class BaseClient(Generic[HttpClientT]):
|
|
|
348
348
|
overall_todo: str,
|
|
349
349
|
task_description: str,
|
|
350
350
|
todos: list[dict],
|
|
351
|
-
deliverables: list[dict],
|
|
352
351
|
history: list[dict] | None = None,
|
|
353
352
|
current_todo_index: int | None = None,
|
|
354
353
|
task_execution_summary: str | None = None,
|
|
@@ -368,7 +367,6 @@ class BaseClient(Generic[HttpClientT]):
|
|
|
368
367
|
overall_todo: Current todo description
|
|
369
368
|
task_description: Overall task description
|
|
370
369
|
todos: List of todo dicts with index, description, status, execution_summary
|
|
371
|
-
deliverables: List of deliverable dicts with description, achieved
|
|
372
370
|
history: List of history dicts with todo_index, todo_description, action_count, summary, completed
|
|
373
371
|
current_todo_index: Index of current todo being executed
|
|
374
372
|
task_execution_summary: Summary of overall task execution
|
|
@@ -402,7 +400,6 @@ class BaseClient(Generic[HttpClientT]):
|
|
|
402
400
|
"overall_todo": overall_todo,
|
|
403
401
|
"task_description": task_description,
|
|
404
402
|
"todos": todos,
|
|
405
|
-
"deliverables": deliverables,
|
|
406
403
|
"history": history or [],
|
|
407
404
|
}
|
|
408
405
|
|
|
@@ -456,6 +453,5 @@ class BaseClient(Generic[HttpClientT]):
|
|
|
456
453
|
|
|
457
454
|
logger.info(
|
|
458
455
|
f"Generate request successful - tokens: {result.prompt_tokens}+{result.completion_tokens}, "
|
|
459
|
-
f"cost: ${result.cost:.6f}"
|
|
460
456
|
)
|
|
461
457
|
return result
|
|
@@ -226,7 +226,6 @@ class SyncClient(BaseClient[httpx.Client]):
|
|
|
226
226
|
overall_todo: str,
|
|
227
227
|
task_description: str,
|
|
228
228
|
todos: list[dict],
|
|
229
|
-
deliverables: list[dict],
|
|
230
229
|
history: list[dict] | None = None,
|
|
231
230
|
current_todo_index: int | None = None,
|
|
232
231
|
task_execution_summary: str | None = None,
|
|
@@ -246,7 +245,6 @@ class SyncClient(BaseClient[httpx.Client]):
|
|
|
246
245
|
overall_todo: Current todo description
|
|
247
246
|
task_description: Overall task description
|
|
248
247
|
todos: List of todo dicts with index, description, status, execution_summary
|
|
249
|
-
deliverables: List of deliverable dicts with description, achieved
|
|
250
248
|
history: List of history dicts with todo_index, todo_description, action_count, summary, completed
|
|
251
249
|
current_todo_index: Index of current todo being executed
|
|
252
250
|
task_execution_summary: Summary of overall task execution
|
|
@@ -272,7 +270,6 @@ class SyncClient(BaseClient[httpx.Client]):
|
|
|
272
270
|
overall_todo=overall_todo,
|
|
273
271
|
task_description=task_description,
|
|
274
272
|
todos=todos,
|
|
275
|
-
deliverables=deliverables,
|
|
276
273
|
history=history,
|
|
277
274
|
current_todo_index=current_todo_index,
|
|
278
275
|
task_execution_summary=task_execution_summary,
|
|
@@ -171,8 +171,14 @@ class PyautoguiActionHandler:
|
|
|
171
171
|
"""Normalize key names for consistency."""
|
|
172
172
|
key = key.strip().lower()
|
|
173
173
|
# Normalize caps lock variations
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
hotkey_variations_mapping = {
|
|
175
|
+
"capslock": ["caps_lock", "caps", "capslock"],
|
|
176
|
+
"pgup": ["page_up", "pageup"],
|
|
177
|
+
"pgdn": ["page_down", "pagedown"],
|
|
178
|
+
}
|
|
179
|
+
for normalized, variations in hotkey_variations_mapping.items():
|
|
180
|
+
if key in variations:
|
|
181
|
+
return normalized
|
|
176
182
|
# Remap ctrl to command on macOS if enabled
|
|
177
183
|
if self.config.macos_ctrl_to_cmd and sys.platform == "darwin" and key == "ctrl":
|
|
178
184
|
return "command"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# Licensed under the MIT License.
|
|
7
7
|
# -----------------------------------------------------------------------------
|
|
8
8
|
|
|
9
|
-
from pydantic import BaseModel
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
10
|
|
|
11
11
|
from .action import Action
|
|
12
12
|
|
|
@@ -56,9 +56,13 @@ class UploadFileResponse(BaseModel):
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
class GenerateResponse(BaseModel):
|
|
59
|
-
"""Response from /
|
|
59
|
+
"""Response from /v1/generate endpoint."""
|
|
60
60
|
|
|
61
61
|
response: str
|
|
62
62
|
prompt_tokens: int
|
|
63
63
|
completion_tokens: int
|
|
64
|
-
cost: float
|
|
64
|
+
cost: float | None = Field(
|
|
65
|
+
default=None,
|
|
66
|
+
deprecated=True,
|
|
67
|
+
description="This field is deprecated",
|
|
68
|
+
)
|
|
@@ -30,7 +30,6 @@ class TestPlanner:
|
|
|
30
30
|
memory.set_task(
|
|
31
31
|
task_description="Test task",
|
|
32
32
|
todos=["Todo 1", "Todo 2"],
|
|
33
|
-
deliverables=["Deliverable 1"],
|
|
34
33
|
)
|
|
35
34
|
return memory
|
|
36
35
|
|
|
@@ -48,7 +47,7 @@ class TestPlanner:
|
|
|
48
47
|
response='{"reasoning": "Start with clicking", "subtask": "Click on button"}',
|
|
49
48
|
prompt_tokens=100,
|
|
50
49
|
completion_tokens=50,
|
|
51
|
-
cost=0.
|
|
50
|
+
cost=0.0,
|
|
52
51
|
)
|
|
53
52
|
|
|
54
53
|
screenshot = b"fake_image_bytes"
|
|
@@ -72,7 +71,7 @@ class TestPlanner:
|
|
|
72
71
|
response='{"reasoning": "No visual needed", "subtask": "Type text"}',
|
|
73
72
|
prompt_tokens=100,
|
|
74
73
|
completion_tokens=50,
|
|
75
|
-
cost=0.
|
|
74
|
+
cost=0.0,
|
|
76
75
|
)
|
|
77
76
|
|
|
78
77
|
result = await planner.initial_plan(
|
|
@@ -111,7 +110,7 @@ class TestPlanner:
|
|
|
111
110
|
response='{"assessment": "Good progress", "success": "yes", "reflection": "Task completed", "subtask_instruction": ""}',
|
|
112
111
|
prompt_tokens=150,
|
|
113
112
|
completion_tokens=75,
|
|
114
|
-
cost=0.
|
|
113
|
+
cost=0.0,
|
|
115
114
|
)
|
|
116
115
|
|
|
117
116
|
result = await planner.reflect(
|
|
@@ -133,7 +132,7 @@ class TestPlanner:
|
|
|
133
132
|
response='{"success": "no", "subtask_instruction": "Try different approach", "reflection": "Need to pivot"}',
|
|
134
133
|
prompt_tokens=100,
|
|
135
134
|
completion_tokens=50,
|
|
136
|
-
cost=0.
|
|
135
|
+
cost=0.0,
|
|
137
136
|
)
|
|
138
137
|
|
|
139
138
|
result = await planner.reflect(
|
|
@@ -152,7 +151,7 @@ class TestPlanner:
|
|
|
152
151
|
response='{"task_summary": "Successfully completed the task"}',
|
|
153
152
|
prompt_tokens=80,
|
|
154
153
|
completion_tokens=20,
|
|
155
|
-
cost=0.
|
|
154
|
+
cost=0.0,
|
|
156
155
|
)
|
|
157
156
|
|
|
158
157
|
result = await planner.summarize(
|