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.
Files changed (107) hide show
  1. {oagi_core-0.10.0 → oagi_core-0.10.1}/PKG-INFO +2 -1
  2. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/tasker_agent_example.py +0 -6
  3. {oagi_core-0.10.0 → oagi_core-0.10.1}/metapackage/pyproject.toml +2 -2
  4. {oagi_core-0.10.0 → oagi_core-0.10.1}/metapackage/uv.lock +5 -5
  5. {oagi_core-0.10.0 → oagi_core-0.10.1}/pyproject.toml +2 -1
  6. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/__init__.py +0 -2
  7. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/memory.py +3 -27
  8. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/models.py +0 -7
  9. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/planner.py +2 -11
  10. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/tasker_agent.py +3 -17
  11. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/agent.py +99 -0
  12. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/async_.py +0 -3
  13. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/base.py +0 -4
  14. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/sync.py +0 -3
  15. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/pyautogui_action_handler.py +8 -2
  16. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/client.py +7 -3
  17. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_planner.py +5 -6
  18. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_planner_memory.py +0 -13
  19. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_taskee_agent.py +5 -5
  20. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_tasker_agent.py +10 -23
  21. {oagi_core-0.10.0 → oagi_core-0.10.1}/uv.lock +71 -28
  22. {oagi_core-0.10.0 → oagi_core-0.10.1}/.github/workflows/ci.yml +0 -0
  23. {oagi_core-0.10.0 → oagi_core-0.10.1}/.github/workflows/release.yml +0 -0
  24. {oagi_core-0.10.0 → oagi_core-0.10.1}/.gitignore +0 -0
  25. {oagi_core-0.10.0 → oagi_core-0.10.1}/.python-version +0 -0
  26. {oagi_core-0.10.0 → oagi_core-0.10.1}/CONTRIBUTING.md +0 -0
  27. {oagi_core-0.10.0 → oagi_core-0.10.1}/LICENSE +0 -0
  28. {oagi_core-0.10.0 → oagi_core-0.10.1}/Makefile +0 -0
  29. {oagi_core-0.10.0 → oagi_core-0.10.1}/README.md +0 -0
  30. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/async_google_weather.py +0 -0
  31. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/execute_task_auto.py +0 -0
  32. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/execute_task_manual.py +0 -0
  33. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/google_weather.py +0 -0
  34. {oagi_core-0.10.0 → oagi_core-0.10.1}/examples/screenshot_with_config.py +0 -0
  35. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/__init__.py +0 -0
  36. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/__init__.py +0 -0
  37. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/default.py +0 -0
  38. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/factories.py +0 -0
  39. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/__init__.py +0 -0
  40. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/agent_observer.py +0 -0
  41. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/events.py +0 -0
  42. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/exporters.py +0 -0
  43. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/observer/protocol.py +0 -0
  44. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/protocol.py +0 -0
  45. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/registry.py +0 -0
  46. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/agent/tasker/taskee_agent.py +0 -0
  47. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/__init__.py +0 -0
  48. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/display.py +0 -0
  49. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/main.py +0 -0
  50. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/server.py +0 -0
  51. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/tracking.py +0 -0
  52. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/cli/utils.py +0 -0
  53. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/client/__init__.py +0 -0
  54. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/exceptions.py +0 -0
  55. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/__init__.py +0 -0
  56. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/_macos.py +0 -0
  57. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/async_pyautogui_action_handler.py +0 -0
  58. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/async_screenshot_maker.py +0 -0
  59. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/pil_image.py +0 -0
  60. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/handler/screenshot_maker.py +0 -0
  61. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/logging.py +0 -0
  62. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/__init__.py +0 -0
  63. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/agent_wrappers.py +0 -0
  64. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/config.py +0 -0
  65. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/main.py +0 -0
  66. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/models.py +0 -0
  67. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/session_store.py +0 -0
  68. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/server/socketio_server.py +0 -0
  69. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/__init__.py +0 -0
  70. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/async_.py +0 -0
  71. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/async_short.py +0 -0
  72. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/base.py +0 -0
  73. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/short.py +0 -0
  74. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/task/sync.py +0 -0
  75. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/__init__.py +0 -0
  76. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/action_handler.py +0 -0
  77. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/async_action_handler.py +0 -0
  78. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/async_image_provider.py +0 -0
  79. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/image.py +0 -0
  80. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/image_provider.py +0 -0
  81. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/__init__.py +0 -0
  82. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/action.py +0 -0
  83. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/image_config.py +0 -0
  84. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/models/step.py +0 -0
  85. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/step_observer.py +0 -0
  86. {oagi_core-0.10.0 → oagi_core-0.10.1}/src/oagi/types/url.py +0 -0
  87. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/__init__.py +0 -0
  88. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/conftest.py +0 -0
  89. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_actor.py +0 -0
  90. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent/test_agent_wrappers.py +0 -0
  91. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent/test_default_agent.py +0 -0
  92. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_agent_registry.py +0 -0
  93. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_actor.py +0 -0
  94. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_client.py +0 -0
  95. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_async_handlers.py +0 -0
  96. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_cli.py +0 -0
  97. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_logging.py +0 -0
  98. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_mac_double_click.py +0 -0
  99. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_observer.py +0 -0
  100. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_pil_image.py +0 -0
  101. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_pyautogui_action_handler.py +0 -0
  102. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_screenshot_maker.py +0 -0
  103. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/__init__.py +0 -0
  104. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_config.py +0 -0
  105. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_session_store.py +0 -0
  106. {oagi_core-0.10.0 → oagi_core-0.10.1}/tests/test_server/test_socketio_integration.py +0 -0
  107. {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.0
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.0"
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.0",
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.0"
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.9.2" }]
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.9.2"
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/4b/68/382a3096645de041f252f5ee8f01d02439f5a419476ab8e84fec638c3592/oagi_core-0.9.2.tar.gz", hash = "sha256:eb18c49f364561c94a26b09c98b855225ac19c19a456170e7a69c1467166f4e5", size = 253368, upload-time = "2025-11-19T04:29:14.85Z" }
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/56/15/f6e55511b78622fea2265eb9137d9c03ebbac102b66ebbf49f26bcd713ab/oagi_core-0.9.2-py3-none-any.whl", hash = "sha256:6f14abeae8338f1703fd30ff7e7ae7316be12c025cb3b30307dfb2d35efbf4fc", size = 75648, upload-time = "2025-11-19T04:29:13.961Z" },
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.0"
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, Deliverable, Todo, TodoHistory, TodoStatus
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/deliverable management
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, todos, and deliverables.
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, list, str | None, str]:
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, deliverables, history,
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, todos, and deliverables for the workflow.
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, deliverables)
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
- if key in ["caps_lock", "caps", "capslock"]:
175
- return "capslock"
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 /v2/generate endpoint."""
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 # in USD
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.001,
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.001,
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.002,
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.001,
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.001,
154
+ cost=0.0,
156
155
  )
157
156
 
158
157
  result = await planner.summarize(