orgo 0.0.12__py3-none-any.whl → 0.0.14__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 +1 -0
- orgo/api/__init__.py +1 -0
- orgo/api/client.py +8 -1
- orgo/computer.py +56 -29
- orgo/project.py +51 -0
- orgo/prompt.py +1 -0
- orgo/utils/__init__.py +1 -0
- orgo/utils/auth.py +1 -0
- {orgo-0.0.12.dist-info → orgo-0.0.14.dist-info}/METADATA +4 -1
- orgo-0.0.14.dist-info/RECORD +12 -0
- {orgo-0.0.12.dist-info → orgo-0.0.14.dist-info}/WHEEL +1 -1
- orgo/adapters/__init__.py +0 -7
- orgo/adapters/anthropic.py +0 -64
- orgo/adapters/base.py +0 -14
- orgo/adapters/openai.py +0 -69
- orgo-0.0.12.dist-info/RECORD +0 -15
- {orgo-0.0.12.dist-info → orgo-0.0.14.dist-info}/top_level.txt +0 -0
orgo/__init__.py
CHANGED
orgo/api/__init__.py
CHANGED
orgo/api/client.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
"""API client for Orgo service"""
|
|
2
1
|
# src/orgo/api/client.py
|
|
2
|
+
"""API client for Orgo service"""
|
|
3
3
|
|
|
4
4
|
import requests
|
|
5
5
|
from typing import Dict, Any, Optional
|
|
@@ -96,6 +96,13 @@ class ApiClient:
|
|
|
96
96
|
"command": command
|
|
97
97
|
})
|
|
98
98
|
|
|
99
|
+
def execute_python(self, project_id: str, code: str, timeout: int = 10) -> Dict[str, Any]:
|
|
100
|
+
"""Execute Python code on the computer"""
|
|
101
|
+
return self._request("POST", f"computers/{project_id}/exec", {
|
|
102
|
+
"code": code,
|
|
103
|
+
"timeout": timeout
|
|
104
|
+
})
|
|
105
|
+
|
|
99
106
|
def wait(self, project_id: str, seconds: float) -> Dict[str, Any]:
|
|
100
107
|
return self._request("POST", f"computers/{project_id}/wait", {
|
|
101
108
|
"seconds": seconds
|
orgo/computer.py
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
"""Computer class for interacting with Orgo virtual environments"""
|
|
2
1
|
# src/orgo/computer.py
|
|
3
|
-
|
|
2
|
+
"""Computer class for interacting with Orgo virtual environments"""
|
|
4
3
|
import os
|
|
5
4
|
import io
|
|
6
5
|
import base64
|
|
6
|
+
import logging
|
|
7
7
|
from typing import Dict, List, Any, Optional, Callable, Union
|
|
8
8
|
from PIL import Image
|
|
9
|
+
from requests.exceptions import RequestException
|
|
9
10
|
|
|
10
11
|
from .api.client import ApiClient
|
|
11
12
|
from .prompt import get_provider
|
|
13
|
+
from .project import ProjectManager
|
|
12
14
|
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
13
16
|
|
|
14
17
|
class Computer:
|
|
15
18
|
def __init__(self, project_id=None, api_key=None, config=None, base_api_url=None):
|
|
@@ -26,16 +29,31 @@ class Computer:
|
|
|
26
29
|
self.base_api_url = base_api_url
|
|
27
30
|
self.api = ApiClient(self.api_key, self.base_api_url)
|
|
28
31
|
|
|
32
|
+
# Look for a saved project ID if none was provided
|
|
33
|
+
if project_id is None:
|
|
34
|
+
project_id = ProjectManager.load_project_id()
|
|
35
|
+
|
|
29
36
|
if project_id:
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
try:
|
|
38
|
+
self.project_id = project_id
|
|
39
|
+
self._info = self.api.connect_computer(project_id)
|
|
40
|
+
except (RequestException, ValueError) as e:
|
|
41
|
+
logger.warning(f"Could not connect to saved project {project_id}: {e}")
|
|
42
|
+
self._create_new_computer(config)
|
|
32
43
|
else:
|
|
33
|
-
|
|
34
|
-
self.project_id = response.get("name")
|
|
35
|
-
self._info = response
|
|
44
|
+
self._create_new_computer(config)
|
|
36
45
|
|
|
46
|
+
def _create_new_computer(self, config=None):
|
|
47
|
+
"""Create a new computer instance and save its ID"""
|
|
48
|
+
response = self.api.create_computer(config)
|
|
49
|
+
self.project_id = response.get("name")
|
|
50
|
+
self._info = response
|
|
51
|
+
|
|
37
52
|
if not self.project_id:
|
|
38
53
|
raise ValueError("Failed to initialize computer: No project ID returned")
|
|
54
|
+
|
|
55
|
+
# Save the project ID for future use
|
|
56
|
+
ProjectManager.save_project_id(self.project_id)
|
|
39
57
|
|
|
40
58
|
def status(self) -> Dict[str, Any]:
|
|
41
59
|
"""Get current computer status"""
|
|
@@ -93,6 +111,37 @@ class Computer:
|
|
|
93
111
|
response = self.api.execute_bash(self.project_id, command)
|
|
94
112
|
return response.get("output", "")
|
|
95
113
|
|
|
114
|
+
def exec(self, code: str, timeout: int = 10) -> Dict[str, Any]:
|
|
115
|
+
"""
|
|
116
|
+
Execute Python code on the remote computer.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
code: Python code to execute
|
|
120
|
+
timeout: Maximum execution time in seconds (default: 10, max: 300)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Dict with keys:
|
|
124
|
+
- success: bool indicating if execution completed without errors
|
|
125
|
+
- output: str containing stdout output
|
|
126
|
+
- error: str containing error message if any
|
|
127
|
+
- error_type: str with exception type name if error occurred
|
|
128
|
+
- timeout: bool indicating if execution timed out
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
result = computer.exec('''
|
|
132
|
+
import os
|
|
133
|
+
print(f"Current directory: {os.getcwd()}")
|
|
134
|
+
print(f"Files: {os.listdir('.')}")
|
|
135
|
+
''')
|
|
136
|
+
|
|
137
|
+
if result['success']:
|
|
138
|
+
print(result['output'])
|
|
139
|
+
else:
|
|
140
|
+
print(f"Error: {result['error']}")
|
|
141
|
+
"""
|
|
142
|
+
response = self.api.execute_python(self.project_id, code, timeout)
|
|
143
|
+
return response
|
|
144
|
+
|
|
96
145
|
def wait(self, seconds: float) -> Dict[str, Any]:
|
|
97
146
|
"""Wait for specified number of seconds"""
|
|
98
147
|
return self.api.wait(self.project_id, seconds)
|
|
@@ -130,28 +179,6 @@ class Computer:
|
|
|
130
179
|
|
|
131
180
|
Returns:
|
|
132
181
|
List of messages from the conversation
|
|
133
|
-
|
|
134
|
-
Examples:
|
|
135
|
-
# Simple usage with environment variables
|
|
136
|
-
computer.prompt("Open Firefox and search for Python tutorials")
|
|
137
|
-
|
|
138
|
-
# With explicit API key
|
|
139
|
-
computer.prompt("Open Terminal and list files", api_key="your-anthropic-key")
|
|
140
|
-
|
|
141
|
-
# With callback for progress updates
|
|
142
|
-
computer.prompt("Create a new text file", callback=my_callback_function)
|
|
143
|
-
|
|
144
|
-
# With thinking enabled (Claude 3.7 Sonnet)
|
|
145
|
-
computer.prompt(
|
|
146
|
-
"Analyze a complex webpage",
|
|
147
|
-
thinking_enabled=True
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
# With custom screenshot management
|
|
151
|
-
computer.prompt(
|
|
152
|
-
"Perform a complex multi-step task",
|
|
153
|
-
max_saved_screenshots=10 # Keep more screenshots for complex tasks
|
|
154
|
-
)
|
|
155
182
|
"""
|
|
156
183
|
# Get the provider instance
|
|
157
184
|
provider_instance = get_provider(provider)
|
orgo/project.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# src/orgo/project.py
|
|
2
|
+
"""Project management for Orgo virtual environments"""
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
class ProjectManager:
|
|
11
|
+
"""Manages project persistence for Orgo computers"""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def load_project_id() -> Optional[str]:
|
|
15
|
+
"""Load project ID from local config file"""
|
|
16
|
+
config_path = ProjectManager._get_config_path()
|
|
17
|
+
|
|
18
|
+
if not os.path.exists(config_path):
|
|
19
|
+
return None
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
with open(config_path, 'r') as f:
|
|
23
|
+
data = json.load(f)
|
|
24
|
+
return data.get('project_id')
|
|
25
|
+
except (json.JSONDecodeError, IOError, OSError) as e:
|
|
26
|
+
logger.warning(f"Error loading project config: {str(e)}")
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def save_project_id(project_id: str) -> None:
|
|
31
|
+
"""Save project ID to local config file"""
|
|
32
|
+
config_dir = ProjectManager._get_project_dir()
|
|
33
|
+
config_path = ProjectManager._get_config_path()
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
os.makedirs(config_dir, exist_ok=True)
|
|
37
|
+
with open(config_path, 'w') as f:
|
|
38
|
+
json.dump({'project_id': project_id}, f, indent=2)
|
|
39
|
+
except (IOError, OSError) as e:
|
|
40
|
+
logger.error(f"Failed to save project ID: {str(e)}")
|
|
41
|
+
raise RuntimeError(f"Failed to save project configuration: {str(e)}") from e
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _get_project_dir() -> str:
|
|
45
|
+
"""Get the project directory path"""
|
|
46
|
+
return os.path.join(os.getcwd(), ".orgo")
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _get_config_path() -> str:
|
|
50
|
+
"""Get the full path to the config file"""
|
|
51
|
+
return os.path.join(ProjectManager._get_project_dir(), "project.json")
|
orgo/prompt.py
CHANGED
orgo/utils/__init__.py
CHANGED
orgo/utils/auth.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: orgo
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.14
|
|
4
4
|
Summary: Computers for AI agents
|
|
5
5
|
Author: Orgo Team
|
|
6
6
|
License: MIT
|
|
@@ -35,6 +35,9 @@ computer.type("Hello world")
|
|
|
35
35
|
computer.key("Enter")
|
|
36
36
|
computer.screenshot() # Returns PIL Image
|
|
37
37
|
|
|
38
|
+
# Execute Python code
|
|
39
|
+
computer.exec("import pyautogui; pyautogui.click(512, 384)")
|
|
40
|
+
|
|
38
41
|
# Cleanup
|
|
39
42
|
computer.shutdown()
|
|
40
43
|
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
orgo/__init__.py,sha256=TlOzDJqRKotAam631MdZcz8ypAqyWrLo-Px8HWLkrD0,131
|
|
2
|
+
orgo/computer.py,sha256=9LtHevWMQiqRmuCxMVg1zXoa9Ja5C0N6Hb9ebbZE1vI,8134
|
|
3
|
+
orgo/project.py,sha256=0rcii4AKLWP4GSbUzfnP4G7TMgmzjm6bj2n-22NIjmk,1779
|
|
4
|
+
orgo/prompt.py,sha256=4qPBrslhidAh7soSJLB5m5bKxobc4FjHF-oaKDIzqWI,18928
|
|
5
|
+
orgo/api/__init__.py,sha256=9Tzb_OPJ5DH7Cg7OrHzpZZUT4ip05alpa9RLDYmnId8,113
|
|
6
|
+
orgo/api/client.py,sha256=PrO_xPU6njxvw9L6ukfHc2el0dswsSamEnOD5ts__Tc,4553
|
|
7
|
+
orgo/utils/__init__.py,sha256=W4G_nwGBf_7jy0w_mfcrkllurYHSRU4B5cMTVYH_uCc,123
|
|
8
|
+
orgo/utils/auth.py,sha256=tPLBJY-6gdBQWLUjUbwIwxHphC3KoRT_XgP3Iykw3Mw,509
|
|
9
|
+
orgo-0.0.14.dist-info/METADATA,sha256=GU8ymFSPku53jJ7k2T8760HHuFG_9Y81Ojwq7MOorCY,822
|
|
10
|
+
orgo-0.0.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
11
|
+
orgo-0.0.14.dist-info/top_level.txt,sha256=q0rYtFji8GbYuhFW8A5Ab9e0j27761IKPhnL0E9xow4,5
|
|
12
|
+
orgo-0.0.14.dist-info/RECORD,,
|
orgo/adapters/__init__.py
DELETED
orgo/adapters/anthropic.py
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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()")
|
orgo/adapters/openai.py
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
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-0.0.12.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
orgo/__init__.py,sha256=SjO41JOwyLmX8K6fKu7LAIOyBk8sAtQKRaNVu2wZVBE,108
|
|
2
|
-
orgo/computer.py,sha256=3S-LoxhgDFiQRajOqeGZkzL93a0l09BEmLO3ADphFFI,7140
|
|
3
|
-
orgo/prompt.py,sha256=WQfde1DXO-W_E59yvSFXK6ct0WOyoy16duSjczm8QQQ,18907
|
|
4
|
-
orgo/adapters/__init__.py,sha256=LMpWJGVHvvSrLPhCJrMSENYSJ8ifWIpTfi88L6aN65I,219
|
|
5
|
-
orgo/adapters/anthropic.py,sha256=KfPD5YWbwECZkpj421rSLCQf9SMr-EJ4nePe2EMXDWA,2342
|
|
6
|
-
orgo/adapters/base.py,sha256=W1dNArKn1ri-X_36KuN-h5yxh1LmjIYCZMkKi9dm020,559
|
|
7
|
-
orgo/adapters/openai.py,sha256=3NFmUYmaCSXHZImMvqj-fVc8oUxxrcU_6voBx2eFf5A,2605
|
|
8
|
-
orgo/api/__init__.py,sha256=nE9fyIZw2q4mGqy063-1RAbBgy_Qhx11gN_swkhmbX8,86
|
|
9
|
-
orgo/api/client.py,sha256=xMTE6kBN9y9ceiTwxkZOg8pi15a2mYk_-AfSBKV6wUg,4264
|
|
10
|
-
orgo/utils/__init__.py,sha256=XSx9W-IPAc7yDnkwgED4v5eBUIQCxmokr_VQzF6LOZs,94
|
|
11
|
-
orgo/utils/auth.py,sha256=mpnaOvM3BGIdZ_j9cTw8K34gPpCeLRrG0rZfoojzONc,484
|
|
12
|
-
orgo-0.0.12.dist-info/METADATA,sha256=ZrleYHDguovTMCfi36X_tyrAJMS-nlaLpFaGE9tl9zM,738
|
|
13
|
-
orgo-0.0.12.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
|
14
|
-
orgo-0.0.12.dist-info/top_level.txt,sha256=q0rYtFji8GbYuhFW8A5Ab9e0j27761IKPhnL0E9xow4,5
|
|
15
|
-
orgo-0.0.12.dist-info/RECORD,,
|
|
File without changes
|