oagi 0.1.0__tar.gz → 0.2.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.

Potentially problematic release.


This version of oagi might be problematic. Click here for more details.

Files changed (51) hide show
  1. oagi-0.2.1/.github/workflows/release.yml +41 -0
  2. {oagi-0.1.0 → oagi-0.2.1}/PKG-INFO +21 -1
  3. oagi-0.2.1/README.md +21 -0
  4. {oagi-0.1.0 → oagi-0.2.1}/examples/execute_task_manual.py +11 -5
  5. oagi-0.2.1/examples/single_step.py +19 -0
  6. {oagi-0.1.0 → oagi-0.2.1}/pyproject.toml +2 -2
  7. oagi-0.2.1/src/oagi/__init__.py +53 -0
  8. oagi-0.2.1/src/oagi/exceptions.py +75 -0
  9. oagi-0.2.1/src/oagi/short_task.py +44 -0
  10. oagi-0.2.1/src/oagi/single_step.py +82 -0
  11. oagi-0.2.1/src/oagi/sync_client.py +289 -0
  12. oagi-0.1.0/src/oagi/short_task.py → oagi-0.2.1/src/oagi/task.py +20 -33
  13. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/image.py +2 -1
  14. {oagi-0.1.0 → oagi-0.2.1}/tests/conftest.py +52 -3
  15. oagi-0.2.1/tests/test_logging.py +334 -0
  16. oagi-0.2.1/tests/test_short_task.py +148 -0
  17. oagi-0.2.1/tests/test_single_step.py +193 -0
  18. oagi-0.2.1/tests/test_sync_client.py +410 -0
  19. oagi-0.2.1/tests/test_task.py +275 -0
  20. {oagi-0.1.0 → oagi-0.2.1}/uv.lock +1 -1
  21. oagi-0.1.0/.claude/settings.local.json +0 -19
  22. oagi-0.1.0/CLAUDE.md +0 -105
  23. oagi-0.1.0/README.md +0 -1
  24. oagi-0.1.0/examples/screenshot.png +0 -0
  25. oagi-0.1.0/examples/test.py +0 -20
  26. oagi-0.1.0/examples/test_screenshot.py +0 -41
  27. oagi-0.1.0/src/oagi/__init__.py +0 -13
  28. oagi-0.1.0/src/oagi/sync_client.py +0 -183
  29. oagi-0.1.0/tests/test_logging.py +0 -321
  30. oagi-0.1.0/tests/test_sync_client.py +0 -331
  31. {oagi-0.1.0 → oagi-0.2.1}/.github/workflows/ci.yml +0 -0
  32. {oagi-0.1.0 → oagi-0.2.1}/.gitignore +0 -0
  33. {oagi-0.1.0 → oagi-0.2.1}/.python-version +0 -0
  34. {oagi-0.1.0 → oagi-0.2.1}/CONTRIBUTING.md +0 -0
  35. {oagi-0.1.0 → oagi-0.2.1}/LICENSE +0 -0
  36. {oagi-0.1.0 → oagi-0.2.1}/Makefile +0 -0
  37. {oagi-0.1.0 → oagi-0.2.1}/examples/execute_task_auto.py +0 -0
  38. {oagi-0.1.0 → oagi-0.2.1}/examples/google_weather.py +0 -0
  39. {oagi-0.1.0 → oagi-0.2.1}/examples/hotel_booking.py +0 -0
  40. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/logging.py +0 -0
  41. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/pyautogui_action_handler.py +0 -0
  42. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/screenshot_maker.py +0 -0
  43. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/__init__.py +0 -0
  44. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/action_handler.py +0 -0
  45. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/image_provider.py +0 -0
  46. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/models/__init__.py +0 -0
  47. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/models/action.py +0 -0
  48. {oagi-0.1.0 → oagi-0.2.1}/src/oagi/types/models/step.py +0 -0
  49. {oagi-0.1.0 → oagi-0.2.1}/tests/__init__.py +0 -0
  50. {oagi-0.1.0 → oagi-0.2.1}/tests/test_pyautogui_action_handler.py +0 -0
  51. {oagi-0.1.0 → oagi-0.2.1}/tests/test_screenshot_maker.py +0 -0
@@ -0,0 +1,41 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ release:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write # For trusted publishing
13
+ contents: write # For GitHub release
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v3
20
+ with:
21
+ enable-cache: true
22
+
23
+ - name: Set up Python
24
+ run: uv python install 3.12
25
+
26
+ - name: Build package
27
+ run: uv build
28
+
29
+ - name: Publish to PyPI
30
+ uses: pypa/gh-action-pypi-publish@release/v1
31
+ with:
32
+ password: ${{ secrets.PYPI_API_TOKEN }}
33
+ # Another option: Use Trusted Publishing (recommended, no token needed)
34
+ # Configure at: https://pypi.org/manage/project/oagi/settings/publishing/
35
+
36
+
37
+ - name: Create GitHub Release
38
+ uses: softprops/action-gh-release@v1
39
+ with:
40
+ files: dist/*
41
+ generate_release_notes: true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: oagi
3
- Version: 0.1.0
3
+ Version: 0.2.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>
@@ -33,3 +33,23 @@ Requires-Dist: pydantic>=2.0.0
33
33
  Description-Content-Type: text/markdown
34
34
 
35
35
  # OAGI Python SDK
36
+
37
+ ## Basic Usage
38
+ ```bash
39
+ pip install oagi # python >= 3.10
40
+ ```
41
+ ```bash
42
+ export OAGI_BASE_URL=""
43
+ export OAGI_API_KEY="sk-xxxx"
44
+ ```
45
+
46
+ ```python
47
+ from oagi import PyautoguiActionHandler, ScreenshotMaker, ShortTask
48
+ short_task = ShortTask()
49
+ is_completed = short_task.auto_mode(
50
+ "Search weather with Google",
51
+ max_steps=5,
52
+ executor=PyautoguiActionHandler(),
53
+ image_provider=(sm := ScreenshotMaker()),
54
+ )
55
+ ```
oagi-0.2.1/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # OAGI Python SDK
2
+
3
+ ## Basic Usage
4
+ ```bash
5
+ pip install oagi # python >= 3.10
6
+ ```
7
+ ```bash
8
+ export OAGI_BASE_URL=""
9
+ export OAGI_API_KEY="sk-xxxx"
10
+ ```
11
+
12
+ ```python
13
+ from oagi import PyautoguiActionHandler, ScreenshotMaker, ShortTask
14
+ short_task = ShortTask()
15
+ is_completed = short_task.auto_mode(
16
+ "Search weather with Google",
17
+ max_steps=5,
18
+ executor=PyautoguiActionHandler(),
19
+ image_provider=(sm := ScreenshotMaker()),
20
+ )
21
+ ```
@@ -6,23 +6,29 @@
6
6
  # Licensed under the MIT License.
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
- from oagi import PyautoguiActionHandler, ScreenshotMaker, ShortTask
9
+ from oagi import PyautoguiActionHandler, ScreenshotMaker, Task
10
10
 
11
11
 
12
12
  def execute_task_manual(task_desc, max_steps=5):
13
13
  # set OAGI_API_KEY and OAGI_BASE_URL
14
14
  # or ShortTask(api_key="your_api_key", base_url="your_base_url")
15
- short_task = ShortTask()
16
- short_task.init_task(task_desc, max_steps=max_steps)
15
+ task = Task()
16
+ task.init_task(task_desc, max_steps=max_steps)
17
17
  executor = (
18
18
  PyautoguiActionHandler()
19
19
  ) # executor = lambda actions: print(actions) for debugging
20
20
  image_provider = ScreenshotMaker()
21
21
 
22
22
  for i in range(max_steps):
23
+ # image can also be bytes
24
+ # with open("test_screenshot.png", "rb") as f:
25
+ # image = f.read()
23
26
  image = image_provider()
24
- # do something with image, maybe save it or OCR then break
25
- step = short_task.step(image)
27
+
28
+ # For additional instructions
29
+ # step = task.step(image, instruction="some instruction")
30
+ step = task.step(image)
31
+
26
32
  # do something with step, maybe print to debug
27
33
  print(f"Step {i}: {step.reason=}")
28
34
 
@@ -0,0 +1,19 @@
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 oagi import single_step
10
+
11
+ step = single_step(
12
+ task_description="Search weather with Google",
13
+ screenshot="some/path/to/local/image", # bytes or Path object or Image object
14
+ instruction="The operating system is macos", # optional instruction
15
+ # api_key="your-api-key", if not set with OAGI_API_KEY env var
16
+ # base_url="https://api.example.com" if not set with OAGI_BASE_URL env var
17
+ )
18
+
19
+ print(step)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oagi"
7
- version = "0.1.0"
7
+ version = "0.2.1"
8
8
  description = "Official API of OpenAGI Foundation"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -32,4 +32,4 @@ dev = [
32
32
  ]
33
33
 
34
34
  [tool.ruff.lint]
35
- extend-select = ["I"]
35
+ extend-select = ["I", "PLC0415"]
@@ -0,0 +1,53 @@
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 oagi.exceptions import (
10
+ APIError,
11
+ AuthenticationError,
12
+ ConfigurationError,
13
+ NetworkError,
14
+ NotFoundError,
15
+ OAGIError,
16
+ RateLimitError,
17
+ RequestTimeoutError,
18
+ ServerError,
19
+ ValidationError,
20
+ )
21
+ from oagi.pyautogui_action_handler import PyautoguiActionHandler
22
+ from oagi.screenshot_maker import ScreenshotMaker
23
+ from oagi.short_task import ShortTask
24
+ from oagi.single_step import single_step
25
+ from oagi.sync_client import ErrorDetail, ErrorResponse, LLMResponse, SyncClient
26
+ from oagi.task import Task
27
+
28
+ __all__ = [
29
+ # Core classes
30
+ "Task",
31
+ "ShortTask",
32
+ "SyncClient",
33
+ # Functions
34
+ "single_step",
35
+ # Handler classes
36
+ "PyautoguiActionHandler",
37
+ "ScreenshotMaker",
38
+ # Response models
39
+ "LLMResponse",
40
+ "ErrorResponse",
41
+ "ErrorDetail",
42
+ # Exceptions
43
+ "OAGIError",
44
+ "APIError",
45
+ "AuthenticationError",
46
+ "ConfigurationError",
47
+ "NetworkError",
48
+ "NotFoundError",
49
+ "RateLimitError",
50
+ "ServerError",
51
+ "RequestTimeoutError",
52
+ "ValidationError",
53
+ ]
@@ -0,0 +1,75 @@
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
+ import httpx
10
+
11
+
12
+ class OAGIError(Exception):
13
+ pass
14
+
15
+
16
+ class APIError(OAGIError):
17
+ def __init__(
18
+ self,
19
+ message: str,
20
+ code: str | None = None,
21
+ status_code: int | None = None,
22
+ response: httpx.Response | None = None,
23
+ ):
24
+ """Initialize APIError.
25
+
26
+ Args:
27
+ message: Human-readable error message
28
+ code: API error code for programmatic handling
29
+ status_code: HTTP status code
30
+ response: Original HTTP response object
31
+ """
32
+ super().__init__(message)
33
+ self.message = message
34
+ self.code = code
35
+ self.status_code = status_code
36
+ self.response = response
37
+
38
+ def __str__(self) -> str:
39
+ if self.code:
40
+ return f"API Error [{self.code}]: {self.message}"
41
+ return f"API Error: {self.message}"
42
+
43
+
44
+ class AuthenticationError(APIError):
45
+ pass
46
+
47
+
48
+ class RateLimitError(APIError):
49
+ pass
50
+
51
+
52
+ class ValidationError(APIError):
53
+ pass
54
+
55
+
56
+ class NotFoundError(APIError):
57
+ pass
58
+
59
+
60
+ class ServerError(APIError):
61
+ pass
62
+
63
+
64
+ class NetworkError(OAGIError):
65
+ def __init__(self, message: str, original_error: Exception | None = None):
66
+ super().__init__(message)
67
+ self.original_error = original_error
68
+
69
+
70
+ class RequestTimeoutError(NetworkError):
71
+ pass
72
+
73
+
74
+ class ConfigurationError(OAGIError):
75
+ pass
@@ -0,0 +1,44 @@
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 .task import Task
11
+ from .types import ActionHandler, ImageProvider
12
+
13
+ logger = get_logger("short_task")
14
+
15
+
16
+ class ShortTask(Task):
17
+ """Task implementation with automatic mode for short-duration tasks."""
18
+
19
+ def auto_mode(
20
+ self,
21
+ task_desc: str,
22
+ max_steps: int = 5,
23
+ executor: ActionHandler = None,
24
+ image_provider: ImageProvider = None,
25
+ ) -> bool:
26
+ """Run the task in automatic mode with the provided executor and image provider."""
27
+ logger.info(
28
+ f"Starting auto mode for task: '{task_desc}' (max_steps: {max_steps})"
29
+ )
30
+ self.init_task(task_desc, max_steps=max_steps)
31
+
32
+ for i in range(max_steps):
33
+ logger.debug(f"Auto mode step {i + 1}/{max_steps}")
34
+ image = image_provider()
35
+ step = self.step(image)
36
+ if step.stop:
37
+ logger.info(f"Auto mode completed successfully after {i + 1} steps")
38
+ return True
39
+ if executor:
40
+ logger.debug(f"Executing {len(step.actions)} actions")
41
+ executor(step.actions)
42
+
43
+ logger.warning(f"Auto mode reached max steps ({max_steps}) without completion")
44
+ return False
@@ -0,0 +1,82 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) OpenAGI Foundation
3
+ # All rights reserved.
4
+ #
5
+ # This file is part of the official API project.
6
+ # Licensed under the MIT License.
7
+ # -----------------------------------------------------------------------------
8
+
9
+ from pathlib import Path
10
+
11
+ from .task import Task
12
+ from .types import Image, Step
13
+
14
+
15
+ def single_step(
16
+ task_description: str,
17
+ screenshot: str | bytes | Path | Image,
18
+ instruction: str | None = None,
19
+ api_key: str | None = None,
20
+ base_url: str | None = None,
21
+ ) -> Step:
22
+ """
23
+ Perform a single-step inference without maintaining task state.
24
+
25
+ This is useful for one-off analyses where you don't need to maintain
26
+ a conversation or task context across multiple steps.
27
+
28
+ Args:
29
+ task_description: Description of the task to perform
30
+ screenshot: Screenshot as Image, bytes, or file path
31
+ instruction: Optional additional instruction for the task
32
+ api_key: OAGI API key (uses environment variable if not provided)
33
+ base_url: OAGI base URL (uses environment variable if not provided)
34
+
35
+ Returns:
36
+ Step: Object containing reasoning, actions, and completion status
37
+
38
+ Example:
39
+ >>> # Using with bytes
40
+ >>> with open("screenshot.png", "rb") as f:
41
+ ... image_bytes = f.read()
42
+ >>> step = single_step(
43
+ ... task_description="Click the submit button",
44
+ ... screenshot=image_bytes
45
+ ... )
46
+
47
+ >>> # Using with file path
48
+ >>> step = single_step(
49
+ ... task_description="Fill in the form",
50
+ ... screenshot=Path("screenshot.png"),
51
+ ... instruction="Use test@example.com for email"
52
+ ... )
53
+
54
+ >>> # Using with Image object
55
+ >>> from oagi.types import Image
56
+ >>> image = Image(...)
57
+ >>> step = single_step(
58
+ ... task_description="Navigate to settings",
59
+ ... screenshot=image
60
+ ... )
61
+ """
62
+ # Convert file paths to bytes
63
+ if isinstance(screenshot, (str, Path)):
64
+ path = Path(screenshot) if isinstance(screenshot, str) else screenshot
65
+ if path.exists():
66
+ with open(path, "rb") as f:
67
+ screenshot_bytes = f.read()
68
+ else:
69
+ raise FileNotFoundError(f"Screenshot file not found: {path}")
70
+ elif isinstance(screenshot, bytes):
71
+ screenshot_bytes = screenshot
72
+ elif isinstance(screenshot, Image):
73
+ screenshot_bytes = screenshot.read()
74
+ else:
75
+ raise ValueError(
76
+ f"screenshot must be Image, bytes, str, or Path, got {type(screenshot)}"
77
+ )
78
+
79
+ # Use Task to perform single step
80
+ with Task(api_key=api_key, base_url=base_url) as task:
81
+ task.init_task(task_description)
82
+ return task.step(screenshot_bytes, instruction=instruction)