orgo 0.0.1__py3-none-any.whl → 0.0.2__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.
orgo/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Orgo SDK: Desktop infrastructure for AI agents"""
2
+
3
+ from .computer import Computer
4
+
5
+ __all__ = ["Computer"]
@@ -0,0 +1,7 @@
1
+ """Adapters for integrating Orgo with AI models"""
2
+
3
+ from .base import BaseAdapter
4
+ from .anthropic import AnthropicAdapter
5
+ from .openai import OpenAIAdapter
6
+
7
+ __all__ = ["BaseAdapter", "AnthropicAdapter", "OpenAIAdapter"]
@@ -0,0 +1,64 @@
1
+ """Adapter for Anthropic's Claude"""
2
+
3
+ from typing import Dict, Any, Optional
4
+ from .base import BaseAdapter
5
+
6
+ class AnthropicAdapter(BaseAdapter):
7
+ def get_tool_definition(self) -> Dict[str, Any]:
8
+ return {
9
+ "name": "computer",
10
+ "description": "Controls a virtual computer to automate tasks",
11
+ "type": "function",
12
+ "parameters": {
13
+ "type": "object",
14
+ "properties": {
15
+ "action": {
16
+ "type": "string",
17
+ "enum": ["left_click", "right_click", "double_click", "type", "key", "scroll", "screenshot"],
18
+ "description": "The action to perform on the computer"
19
+ },
20
+ "coordinate": {
21
+ "type": "array",
22
+ "items": {"type": "number"},
23
+ "description": "The x,y coordinates for click actions",
24
+ "minItems": 2,
25
+ "maxItems": 2
26
+ },
27
+ "text": {
28
+ "type": "string",
29
+ "description": "The text to type or key to press"
30
+ },
31
+ "direction": {
32
+ "type": "string",
33
+ "enum": ["up", "down", "left", "right"],
34
+ "description": "The direction to scroll"
35
+ },
36
+ "amount": {
37
+ "type": "number",
38
+ "description": "The amount to scroll"
39
+ }
40
+ },
41
+ "required": ["action"],
42
+ "additionalProperties": False
43
+ }
44
+ }
45
+
46
+ def format_result(self, tool_id: str, output: Optional[str] = None, error: Optional[str] = None) -> Dict[str, Any]:
47
+ screenshot = self.computer.get_base64()
48
+ result = {
49
+ "type": "tool_result",
50
+ "id": tool_id,
51
+ "content": {
52
+ "type": "image",
53
+ "source": {
54
+ "type": "base64",
55
+ "media_type": "image/png",
56
+ "data": screenshot
57
+ }
58
+ }
59
+ }
60
+
61
+ if error:
62
+ result["error"] = error
63
+
64
+ return result
orgo/adapters/base.py ADDED
@@ -0,0 +1,14 @@
1
+ """Base adapter for AI model integration"""
2
+
3
+ from typing import Dict, Any, Optional
4
+ from ..computer import Computer
5
+
6
+ class BaseAdapter:
7
+ def __init__(self, computer: Computer):
8
+ self.computer = computer
9
+
10
+ def get_tool_definition(self) -> Dict[str, Any]:
11
+ raise NotImplementedError("Subclasses must implement get_tool_definition()")
12
+
13
+ def format_result(self, tool_id: str, output: Optional[str] = None, error: Optional[str] = None) -> Dict[str, Any]:
14
+ raise NotImplementedError("Subclasses must implement format_result()")
@@ -0,0 +1,69 @@
1
+ """Adapter for OpenAI models"""
2
+
3
+ from typing import Dict, Any, Optional
4
+ from .base import BaseAdapter
5
+
6
+ class OpenAIAdapter(BaseAdapter):
7
+ def get_tool_definition(self) -> Dict[str, Any]:
8
+ return {
9
+ "type": "function",
10
+ "function": {
11
+ "name": "computer",
12
+ "description": "Controls a virtual computer to automate tasks",
13
+ "parameters": {
14
+ "type": "object",
15
+ "properties": {
16
+ "action": {
17
+ "type": "string",
18
+ "enum": ["click", "right_click", "double_click", "type", "key", "scroll", "screenshot"],
19
+ "description": "The action to perform on the computer"
20
+ },
21
+ "x": {
22
+ "type": "number",
23
+ "description": "The x coordinate for click actions"
24
+ },
25
+ "y": {
26
+ "type": "number",
27
+ "description": "The y coordinate for click actions"
28
+ },
29
+ "text": {
30
+ "type": "string",
31
+ "description": "The text to type or key to press"
32
+ },
33
+ "direction": {
34
+ "type": "string",
35
+ "enum": ["up", "down", "left", "right"],
36
+ "description": "The direction to scroll"
37
+ },
38
+ "amount": {
39
+ "type": "number",
40
+ "description": "The amount to scroll"
41
+ }
42
+ },
43
+ "required": ["action"],
44
+ "additionalProperties": False
45
+ }
46
+ }
47
+ }
48
+
49
+ def format_result(self, tool_id: str, output: Optional[str] = None, error: Optional[str] = None) -> Dict[str, Any]:
50
+ screenshot = self.computer.get_base64()
51
+ result = {
52
+ "tool_call_id": tool_id,
53
+ "content": [
54
+ {
55
+ "type": "image_url",
56
+ "image_url": {
57
+ "url": f"data:image/png;base64,{screenshot}"
58
+ }
59
+ }
60
+ ]
61
+ }
62
+
63
+ if error:
64
+ result["content"].insert(0, {
65
+ "type": "text",
66
+ "text": f"Error: {error}"
67
+ })
68
+
69
+ return result
orgo/api/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """API package for Orgo SDK"""
2
+
3
+ from .client import ApiClient
4
+
5
+ __all__ = ["ApiClient"]
orgo/api/client.py ADDED
@@ -0,0 +1,101 @@
1
+ """Low-level API client for Orgo service"""
2
+
3
+ import requests
4
+ from typing import Dict, Any, Optional
5
+
6
+ from orgo.utils.auth import get_api_key
7
+
8
+ class ApiClient:
9
+ BASE_URL = "https://www.orgo.ai/api"
10
+
11
+ def __init__(self, api_key: Optional[str] = None):
12
+ self.api_key = get_api_key(api_key)
13
+ self.session = requests.Session()
14
+ self.session.headers.update({
15
+ "Authorization": f"Bearer {self.api_key}",
16
+ "Content-Type": "application/json",
17
+ "Accept": "application/json"
18
+ })
19
+
20
+ def _request(self, method: str, endpoint: str, data: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
21
+ url = f"{self.BASE_URL}/{endpoint}"
22
+
23
+ try:
24
+ if method.upper() == "GET":
25
+ response = self.session.get(url, params=data)
26
+ else:
27
+ response = self.session.request(method, url, json=data)
28
+
29
+ response.raise_for_status()
30
+ return response.json()
31
+ except requests.exceptions.RequestException as e:
32
+ if hasattr(e, 'response') and e.response is not None:
33
+ error_message = f"API error: {e.response.status_code}"
34
+ try:
35
+ error_data = e.response.json()
36
+ if 'error' in error_data:
37
+ error_message += f" - {error_data['error']}"
38
+ except ValueError:
39
+ pass
40
+ raise Exception(error_message) from e
41
+ raise Exception(f"Connection error: {str(e)}") from e
42
+
43
+ # Computer lifecycle methods
44
+ def create_computer(self) -> Dict[str, Any]:
45
+ return self._request("POST", "computers")
46
+
47
+ def connect_computer(self, project_id: str) -> Dict[str, Any]:
48
+ return self._request("GET", f"computers/{project_id}")
49
+
50
+ def get_status(self, project_id: str) -> Dict[str, Any]:
51
+ return self._request("GET", f"computers/{project_id}/status")
52
+
53
+ def restart_computer(self, project_id: str) -> Dict[str, Any]:
54
+ return self._request("POST", f"computers/{project_id}/restart")
55
+
56
+ def shutdown_computer(self, project_id: str) -> Dict[str, Any]:
57
+ return self._request("POST", f"computers/{project_id}/shutdown")
58
+
59
+ # Computer control methods
60
+ def left_click(self, project_id: str, x: int, y: int) -> Dict[str, Any]:
61
+ return self._request("POST", f"computers/{project_id}/click", {
62
+ "button": "left", "x": x, "y": y
63
+ })
64
+
65
+ def right_click(self, project_id: str, x: int, y: int) -> Dict[str, Any]:
66
+ return self._request("POST", f"computers/{project_id}/click", {
67
+ "button": "right", "x": x, "y": y
68
+ })
69
+
70
+ def double_click(self, project_id: str, x: int, y: int) -> Dict[str, Any]:
71
+ return self._request("POST", f"computers/{project_id}/click", {
72
+ "button": "left", "x": x, "y": y, "double": True
73
+ })
74
+
75
+ def scroll(self, project_id: str, direction: str, amount: int) -> Dict[str, Any]:
76
+ return self._request("POST", f"computers/{project_id}/scroll", {
77
+ "direction": direction, "amount": amount
78
+ })
79
+
80
+ def type_text(self, project_id: str, text: str) -> Dict[str, Any]:
81
+ return self._request("POST", f"computers/{project_id}/type", {
82
+ "text": text
83
+ })
84
+
85
+ def key_press(self, project_id: str, key: str) -> Dict[str, Any]:
86
+ return self._request("POST", f"computers/{project_id}/key", {
87
+ "key": key
88
+ })
89
+
90
+ def get_screenshot(self, project_id: str) -> Dict[str, Any]:
91
+ return self._request("GET", f"computers/{project_id}/screenshot")
92
+
93
+ def execute_bash(self, project_id: str, command: str) -> Dict[str, Any]:
94
+ return self._request("POST", f"computers/{project_id}/bash", {
95
+ "command": command
96
+ })
97
+
98
+ def wait(self, project_id: str, seconds: float) -> Dict[str, Any]:
99
+ return self._request("POST", f"computers/{project_id}/wait", {
100
+ "seconds": seconds
101
+ })
orgo/computer.py ADDED
@@ -0,0 +1,84 @@
1
+ """Computer class for interacting with Orgo virtual environments"""
2
+
3
+ import os
4
+ import io
5
+ import base64
6
+ from typing import Dict, Any, Optional
7
+ from PIL import Image
8
+
9
+ from .api.client import ApiClient
10
+
11
+ class Computer:
12
+ def __init__(self, project_id=None, api_key=None):
13
+ self.api = ApiClient(api_key or os.environ.get("ORGO_API_KEY"))
14
+
15
+ if project_id:
16
+ self.project_id = project_id
17
+ self._info = self.api.connect_computer(project_id)
18
+ else:
19
+ response = self.api.create_computer()
20
+ self.project_id = response.get("project_id")
21
+ self._info = response
22
+
23
+ if not self.project_id:
24
+ raise ValueError("Failed to initialize computer: No project ID returned")
25
+
26
+ def status(self) -> Dict[str, Any]:
27
+ """Get current computer status"""
28
+ return self.api.get_status(self.project_id)
29
+
30
+ def restart(self) -> Dict[str, Any]:
31
+ """Restart the computer"""
32
+ return self.api.restart_computer(self.project_id)
33
+
34
+ def shutdown(self) -> Dict[str, Any]:
35
+ """Terminate the computer instance"""
36
+ return self.api.shutdown_computer(self.project_id)
37
+
38
+ # Navigation methods
39
+ def left_click(self, x: int, y: int) -> Dict[str, Any]:
40
+ """Perform left mouse click at specified coordinates"""
41
+ return self.api.left_click(self.project_id, x, y)
42
+
43
+ def right_click(self, x: int, y: int) -> Dict[str, Any]:
44
+ """Perform right mouse click at specified coordinates"""
45
+ return self.api.right_click(self.project_id, x, y)
46
+
47
+ def double_click(self, x: int, y: int) -> Dict[str, Any]:
48
+ """Perform double click at specified coordinates"""
49
+ return self.api.double_click(self.project_id, x, y)
50
+
51
+ def scroll(self, direction: str = "down", amount: int = 1) -> Dict[str, Any]:
52
+ """Scroll in specified direction and amount"""
53
+ return self.api.scroll(self.project_id, direction, amount)
54
+
55
+ # Input methods
56
+ def type(self, text: str) -> Dict[str, Any]:
57
+ """Type the specified text"""
58
+ return self.api.type_text(self.project_id, text)
59
+
60
+ def key(self, key: str) -> Dict[str, Any]:
61
+ """Press a key or key combination (e.g., "Enter", "ctrl+c")"""
62
+ return self.api.key_press(self.project_id, key)
63
+
64
+ # View methods
65
+ def screenshot(self) -> Image.Image:
66
+ """Capture screenshot and return as PIL Image"""
67
+ response = self.api.get_screenshot(self.project_id)
68
+ img_data = base64.b64decode(response.get("screenshot", ""))
69
+ return Image.open(io.BytesIO(img_data))
70
+
71
+ def screenshot_base64(self) -> str:
72
+ """Capture screenshot and return as base64 string"""
73
+ response = self.api.get_screenshot(self.project_id)
74
+ return response.get("screenshot", "")
75
+
76
+ # Execution methods
77
+ def bash(self, command: str) -> str:
78
+ """Execute a bash command and return output"""
79
+ response = self.api.execute_bash(self.project_id, command)
80
+ return response.get("output", "")
81
+
82
+ def wait(self, seconds: float) -> Dict[str, Any]:
83
+ """Wait for specified number of seconds"""
84
+ return self.api.wait(self.project_id, seconds)
orgo/utils/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Utility functions for Orgo SDK"""
2
+
3
+ from .auth import get_api_key
4
+
5
+ __all__ = ["get_api_key"]
orgo/utils/auth.py ADDED
@@ -0,0 +1,16 @@
1
+ """Authentication utilities for Orgo SDK"""
2
+
3
+ import os
4
+ from typing import Optional
5
+
6
+ def get_api_key(api_key: Optional[str] = None) -> str:
7
+ """Get the Orgo API key from parameters or environment"""
8
+ key = api_key or os.environ.get("ORGO_API_KEY")
9
+
10
+ if not key:
11
+ raise ValueError(
12
+ "API key required. Set ORGO_API_KEY environment variable or pass api_key parameter. "
13
+ "Get a key at https://www.orgo.ai/start"
14
+ )
15
+
16
+ return key
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.2
2
+ Name: orgo
3
+ Version: 0.0.2
4
+ Summary: Desktop infrastructure for AI agents
5
+ Author: Orgo Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://www.orgo.ai
8
+ Project-URL: Documentation, https://docs.orgo.ai
9
+ Requires-Python: >=3.7
10
+ Requires-Dist: requests>=2.25.0
11
+ Requires-Dist: pillow>=8.0.0
@@ -0,0 +1,14 @@
1
+ orgo/__init__.py,sha256=SjO41JOwyLmX8K6fKu7LAIOyBk8sAtQKRaNVu2wZVBE,108
2
+ orgo/computer.py,sha256=WJgCESNwDf4aU454upvwuAGwQgCD1zHti7faNOv73X0,3249
3
+ orgo/adapters/__init__.py,sha256=LMpWJGVHvvSrLPhCJrMSENYSJ8ifWIpTfi88L6aN65I,219
4
+ orgo/adapters/anthropic.py,sha256=KfPD5YWbwECZkpj421rSLCQf9SMr-EJ4nePe2EMXDWA,2342
5
+ orgo/adapters/base.py,sha256=W1dNArKn1ri-X_36KuN-h5yxh1LmjIYCZMkKi9dm020,559
6
+ orgo/adapters/openai.py,sha256=3NFmUYmaCSXHZImMvqj-fVc8oUxxrcU_6voBx2eFf5A,2605
7
+ orgo/api/__init__.py,sha256=nE9fyIZw2q4mGqy063-1RAbBgy_Qhx11gN_swkhmbX8,86
8
+ orgo/api/client.py,sha256=c-Wiymvre4v7psdgvu2aKZfBc7R8QimHfu5UrQl0H2s,4057
9
+ orgo/utils/__init__.py,sha256=XSx9W-IPAc7yDnkwgED4v5eBUIQCxmokr_VQzF6LOZs,94
10
+ orgo/utils/auth.py,sha256=mpnaOvM3BGIdZ_j9cTw8K34gPpCeLRrG0rZfoojzONc,484
11
+ orgo-0.0.2.dist-info/METADATA,sha256=8NEJnaANllG7P4d4kg18tisNiaMjPC5q-zR3I3aavio,301
12
+ orgo-0.0.2.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
13
+ orgo-0.0.2.dist-info/top_level.txt,sha256=q0rYtFji8GbYuhFW8A5Ab9e0j27761IKPhnL0E9xow4,5
14
+ orgo-0.0.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1 @@
1
+ orgo
@@ -1,6 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: orgo
3
- Version: 0.0.1
4
- Author: Your Name
5
- License: MIT
6
- Requires-Python: >=3.6
@@ -1,4 +0,0 @@
1
- orgo-0.0.1.dist-info/METADATA,sha256=QmJjGIc_6GqPvO_7WUMBXJKMpeqgKXjJInHr7gSm0y4,102
2
- orgo-0.0.1.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
3
- orgo-0.0.1.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
4
- orgo-0.0.1.dist-info/RECORD,,
@@ -1 +0,0 @@
1
-