opencomputer-sdk 0.4.4__tar.gz → 0.4.6__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.
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/.gitignore +11 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/PKG-INFO +1 -1
- opencomputer_sdk-0.4.6/examples/test_default_template.py +253 -0
- opencomputer_sdk-0.4.6/examples/test_exec.py +138 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/opencomputer/__init__.py +9 -3
- opencomputer_sdk-0.4.6/opencomputer/agent.py +333 -0
- opencomputer_sdk-0.4.6/opencomputer/exec.py +136 -0
- opencomputer_sdk-0.4.6/opencomputer/sandbox.py +462 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/pyproject.toml +1 -1
- opencomputer_sdk-0.4.4/opencomputer/sandbox.py +0 -228
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/README.md +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/run_all_tests.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_commands.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_concurrent.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_domain_tls.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_environment.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_file_ops.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_multi_template.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_python_sdk.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_reconnect.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/examples/test_timeout.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/opencomputer/commands.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/opencomputer/filesystem.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/opencomputer/pty.py +0 -0
- {opencomputer_sdk-0.4.4 → opencomputer_sdk-0.4.6}/opencomputer/template.py +0 -0
|
@@ -43,6 +43,17 @@ sdks/typescript/examples/loom/
|
|
|
43
43
|
*.mp4
|
|
44
44
|
*.gif
|
|
45
45
|
|
|
46
|
+
# Terraform
|
|
47
|
+
deploy/terraform/.terraform/
|
|
48
|
+
deploy/terraform/.terraform.lock.hcl
|
|
49
|
+
deploy/terraform/terraform.tfstate*
|
|
50
|
+
deploy/terraform/terraform.tfvars
|
|
51
|
+
|
|
52
|
+
# Dev environment state
|
|
53
|
+
deploy/ec2/.dev-env-state*
|
|
54
|
+
deploy/ec2/*.pem
|
|
55
|
+
|
|
46
56
|
# Temp files
|
|
47
57
|
*.tmp
|
|
48
58
|
*.log
|
|
59
|
+
delme
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opencomputer-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.6
|
|
4
4
|
Summary: Python SDK for OpenComputer - cloud sandbox platform
|
|
5
5
|
Project-URL: Homepage, https://github.com/diggerhq/opensandbox
|
|
6
6
|
Project-URL: Repository, https://github.com/diggerhq/opensandbox
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Default Template Verification Test
|
|
4
|
+
|
|
5
|
+
Verifies that the "default" template image contains all expected packages:
|
|
6
|
+
1. Python 3 + pip + venv
|
|
7
|
+
2. Node.js 20 + npm
|
|
8
|
+
3. Build tools (gcc, g++, make, cmake)
|
|
9
|
+
4. Git + git-lfs
|
|
10
|
+
5. Common utilities (curl, wget, jq, tar, zip, unzip, etc.)
|
|
11
|
+
6. System libraries (libssl, libffi, zlib, sqlite3)
|
|
12
|
+
7. Locale (en_US.UTF-8 available)
|
|
13
|
+
8. Workspace directory
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python examples/test_default_template.py
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
24
|
+
from opencomputer import Sandbox
|
|
25
|
+
|
|
26
|
+
GREEN = "\033[32m"
|
|
27
|
+
RED = "\033[31m"
|
|
28
|
+
BOLD = "\033[1m"
|
|
29
|
+
DIM = "\033[2m"
|
|
30
|
+
RESET = "\033[0m"
|
|
31
|
+
|
|
32
|
+
passed = 0
|
|
33
|
+
failed = 0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def green(msg: str) -> None:
|
|
37
|
+
print(f"{GREEN}✓ {msg}{RESET}")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def red(msg: str) -> None:
|
|
41
|
+
print(f"{RED}✗ {msg}{RESET}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def bold(msg: str) -> None:
|
|
45
|
+
print(f"{BOLD}{msg}{RESET}")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def dim(msg: str) -> None:
|
|
49
|
+
print(f"{DIM} {msg}{RESET}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def check(desc: str, condition: bool, detail: str = "") -> None:
|
|
53
|
+
global passed, failed
|
|
54
|
+
if condition:
|
|
55
|
+
green(desc)
|
|
56
|
+
passed += 1
|
|
57
|
+
else:
|
|
58
|
+
red(f"{desc} ({detail})" if detail else desc)
|
|
59
|
+
failed += 1
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def expect_command(
|
|
63
|
+
sandbox: Sandbox,
|
|
64
|
+
desc: str,
|
|
65
|
+
cmd: str,
|
|
66
|
+
contains: str | None = None,
|
|
67
|
+
) -> str:
|
|
68
|
+
"""Run a command and check it exits 0 and stdout contains expected substring."""
|
|
69
|
+
result = await sandbox.commands.run(cmd)
|
|
70
|
+
out = (result.stdout.strip() or result.stderr.strip())
|
|
71
|
+
dim(f"$ {cmd}")
|
|
72
|
+
dim(f" → {out}")
|
|
73
|
+
|
|
74
|
+
if result.exit_code != 0:
|
|
75
|
+
check(desc, False, f"exit code {result.exit_code}")
|
|
76
|
+
return out
|
|
77
|
+
|
|
78
|
+
if contains is not None:
|
|
79
|
+
check(desc, contains.lower() in out.lower(),
|
|
80
|
+
f'expected "{contains}" in output')
|
|
81
|
+
else:
|
|
82
|
+
check(desc, True)
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
async def main() -> None:
|
|
87
|
+
global passed, failed
|
|
88
|
+
|
|
89
|
+
bold("\n╔══════════════════════════════════════════════════╗")
|
|
90
|
+
bold("║ Default Template Verification Test ║")
|
|
91
|
+
bold("╚══════════════════════════════════════════════════╝\n")
|
|
92
|
+
|
|
93
|
+
sandbox = None
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
sandbox = await Sandbox.create(template="default", timeout=120)
|
|
97
|
+
green(f"Created sandbox: {sandbox.sandbox_id}")
|
|
98
|
+
print()
|
|
99
|
+
|
|
100
|
+
# ── 1. Python ──
|
|
101
|
+
bold("━━━ 1. Python 3 ━━━\n")
|
|
102
|
+
|
|
103
|
+
await expect_command(sandbox, "python3 is installed",
|
|
104
|
+
"python3 --version", contains="Python 3")
|
|
105
|
+
await expect_command(sandbox, "python symlink works",
|
|
106
|
+
"python --version", contains="Python 3")
|
|
107
|
+
await expect_command(sandbox, "pip3 is installed",
|
|
108
|
+
"pip3 --version", contains="pip")
|
|
109
|
+
await expect_command(sandbox, "python3-venv is available",
|
|
110
|
+
"python3 -m venv --help 2>&1 | head -1", contains="usage")
|
|
111
|
+
|
|
112
|
+
pip_install = await sandbox.commands.run(
|
|
113
|
+
"pip3 install --no-cache-dir cowsay 2>&1", timeout=30)
|
|
114
|
+
check("pip install works", pip_install.exit_code == 0,
|
|
115
|
+
f"exit {pip_install.exit_code}")
|
|
116
|
+
cowsay = await sandbox.commands.run(
|
|
117
|
+
"python3 -c 'import cowsay; print(\"pip-ok\")'")
|
|
118
|
+
check("installed Python package importable",
|
|
119
|
+
"pip-ok" in cowsay.stdout.strip())
|
|
120
|
+
print()
|
|
121
|
+
|
|
122
|
+
# ── 2. Node.js ──
|
|
123
|
+
bold("━━━ 2. Node.js 20 + npm ━━━\n")
|
|
124
|
+
|
|
125
|
+
node_version = await expect_command(sandbox, "node is installed",
|
|
126
|
+
"node --version")
|
|
127
|
+
check("Node.js is v20.x", node_version.startswith("v20"),
|
|
128
|
+
f"got {node_version}")
|
|
129
|
+
await expect_command(sandbox, "npm is installed", "npm --version")
|
|
130
|
+
|
|
131
|
+
await sandbox.commands.run(
|
|
132
|
+
"mkdir -p /tmp/npm-test && cd /tmp/npm-test && npm init -y 2>&1",
|
|
133
|
+
timeout=10)
|
|
134
|
+
npm_install = await sandbox.commands.run(
|
|
135
|
+
"cd /tmp/npm-test && npm install is-odd 2>&1", timeout=30)
|
|
136
|
+
check("npm install works", npm_install.exit_code == 0,
|
|
137
|
+
f"exit {npm_install.exit_code}")
|
|
138
|
+
node_run = await sandbox.commands.run(
|
|
139
|
+
"""node -e "console.log(require('is-odd')(3))" """,
|
|
140
|
+
cwd="/tmp/npm-test")
|
|
141
|
+
check("installed npm package works",
|
|
142
|
+
node_run.stdout.strip() == "true",
|
|
143
|
+
f'got "{node_run.stdout.strip()}"')
|
|
144
|
+
print()
|
|
145
|
+
|
|
146
|
+
# ── 3. Build tools ──
|
|
147
|
+
bold("━━━ 3. Build tools ━━━\n")
|
|
148
|
+
|
|
149
|
+
await expect_command(sandbox, "gcc is installed",
|
|
150
|
+
"gcc --version 2>&1 | head -1", contains="gcc")
|
|
151
|
+
await expect_command(sandbox, "g++ is installed",
|
|
152
|
+
"g++ --version 2>&1 | head -1", contains="g++")
|
|
153
|
+
await expect_command(sandbox, "make is installed",
|
|
154
|
+
"make --version 2>&1 | head -1", contains="make")
|
|
155
|
+
await expect_command(sandbox, "cmake is installed",
|
|
156
|
+
"cmake --version 2>&1 | head -1", contains="cmake")
|
|
157
|
+
await expect_command(sandbox, "pkg-config is installed",
|
|
158
|
+
"pkg-config --version")
|
|
159
|
+
|
|
160
|
+
await sandbox.files.write("/tmp/hello.c",
|
|
161
|
+
'#include <stdio.h>\nint main() { printf("compiled-ok\\n"); return 0; }')
|
|
162
|
+
compile_result = await sandbox.commands.run(
|
|
163
|
+
"gcc -o /tmp/hello /tmp/hello.c && /tmp/hello")
|
|
164
|
+
check("C compilation + execution works",
|
|
165
|
+
compile_result.stdout.strip() == "compiled-ok",
|
|
166
|
+
f'got "{compile_result.stdout.strip()}"')
|
|
167
|
+
print()
|
|
168
|
+
|
|
169
|
+
# ── 4. Git ──
|
|
170
|
+
bold("━━━ 4. Git ━━━\n")
|
|
171
|
+
|
|
172
|
+
await expect_command(sandbox, "git is installed",
|
|
173
|
+
"git --version", contains="git version")
|
|
174
|
+
await expect_command(sandbox, "git-lfs is installed",
|
|
175
|
+
"git lfs version 2>&1 | head -1", contains="git-lfs")
|
|
176
|
+
print()
|
|
177
|
+
|
|
178
|
+
# ── 5. Networking & utilities ──
|
|
179
|
+
bold("━━━ 5. Networking & common utilities ━━━\n")
|
|
180
|
+
|
|
181
|
+
await expect_command(sandbox, "curl is installed",
|
|
182
|
+
"curl --version 2>&1 | head -1", contains="curl")
|
|
183
|
+
await expect_command(sandbox, "wget is installed",
|
|
184
|
+
"wget --version 2>&1 | head -1", contains="wget")
|
|
185
|
+
await expect_command(sandbox, "ssh client is installed",
|
|
186
|
+
"ssh -V 2>&1", contains="OpenSSH")
|
|
187
|
+
await expect_command(sandbox, "jq is installed",
|
|
188
|
+
"jq --version", contains="jq")
|
|
189
|
+
await expect_command(sandbox, "tar is installed",
|
|
190
|
+
"tar --version 2>&1 | head -1", contains="tar")
|
|
191
|
+
await expect_command(sandbox, "zip is installed",
|
|
192
|
+
"zip --version 2>&1 | head -2 | tail -1", contains="zip")
|
|
193
|
+
await expect_command(sandbox, "unzip is installed",
|
|
194
|
+
"unzip -v 2>&1 | head -1", contains="unzip")
|
|
195
|
+
await expect_command(sandbox, "rsync is installed",
|
|
196
|
+
"rsync --version 2>&1 | head -1", contains="rsync")
|
|
197
|
+
await expect_command(sandbox, "htop is installed",
|
|
198
|
+
"htop --version 2>&1 | head -1", contains="htop")
|
|
199
|
+
await expect_command(sandbox, "tree is installed",
|
|
200
|
+
"tree --version 2>&1", contains="tree")
|
|
201
|
+
print()
|
|
202
|
+
|
|
203
|
+
# ── 6. System libraries ──
|
|
204
|
+
bold("━━━ 6. System libraries ━━━\n")
|
|
205
|
+
|
|
206
|
+
await expect_command(sandbox, "sqlite3 is installed",
|
|
207
|
+
"sqlite3 --version 2>&1 | head -1")
|
|
208
|
+
await expect_command(sandbox, "libssl headers present",
|
|
209
|
+
"test -f /usr/include/openssl/ssl.h && echo ok",
|
|
210
|
+
contains="ok")
|
|
211
|
+
await expect_command(
|
|
212
|
+
sandbox, "libffi headers present",
|
|
213
|
+
"test -f /usr/include/ffi.h && echo ok "
|
|
214
|
+
"|| (dpkg -L libffi-dev 2>/dev/null | grep ffi.h | head -1)",
|
|
215
|
+
contains="ffi")
|
|
216
|
+
await expect_command(sandbox, "zlib headers present",
|
|
217
|
+
"test -f /usr/include/zlib.h && echo ok",
|
|
218
|
+
contains="ok")
|
|
219
|
+
print()
|
|
220
|
+
|
|
221
|
+
# ── 7. Locale ──
|
|
222
|
+
bold("━━━ 7. Locale ━━━\n")
|
|
223
|
+
|
|
224
|
+
await expect_command(sandbox, "en_US.UTF-8 locale is available",
|
|
225
|
+
"locale -a 2>&1 | grep -i en_US.utf8",
|
|
226
|
+
contains="en_US")
|
|
227
|
+
print()
|
|
228
|
+
|
|
229
|
+
# ── 8. Workspace ──
|
|
230
|
+
bold("━━━ 8. Workspace directory ━━━\n")
|
|
231
|
+
|
|
232
|
+
await expect_command(sandbox, "/workspace exists",
|
|
233
|
+
"test -d /workspace && echo ok", contains="ok")
|
|
234
|
+
print()
|
|
235
|
+
|
|
236
|
+
except Exception as e:
|
|
237
|
+
red(f"Fatal error: {e}")
|
|
238
|
+
failed += 1
|
|
239
|
+
finally:
|
|
240
|
+
if sandbox:
|
|
241
|
+
await sandbox.kill()
|
|
242
|
+
green("Sandbox killed")
|
|
243
|
+
|
|
244
|
+
# --- Summary ---
|
|
245
|
+
bold("========================================")
|
|
246
|
+
bold(f" Results: {passed} passed, {failed} failed")
|
|
247
|
+
bold("========================================\n")
|
|
248
|
+
if failed > 0:
|
|
249
|
+
sys.exit(1)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
if __name__ == "__main__":
|
|
253
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""
|
|
2
|
+
test_exec.py — End-to-end test for the session-based exec API (Python SDK)
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
cd sdks/python
|
|
6
|
+
pip install -e .
|
|
7
|
+
python examples/test_exec.py
|
|
8
|
+
|
|
9
|
+
Environment:
|
|
10
|
+
OPENCOMPUTER_API_URL (default: http://localhost:8080)
|
|
11
|
+
OPENCOMPUTER_API_KEY (default: opensandbox-dev)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
from opencomputer import Sandbox
|
|
18
|
+
|
|
19
|
+
API_URL = os.environ.get("OPENCOMPUTER_API_URL", "http://localhost:8080")
|
|
20
|
+
API_KEY = os.environ.get("OPENCOMPUTER_API_KEY", "opensandbox-dev")
|
|
21
|
+
|
|
22
|
+
passed = 0
|
|
23
|
+
failed = 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def check(condition: bool, msg: str):
|
|
27
|
+
global passed, failed
|
|
28
|
+
if condition:
|
|
29
|
+
passed += 1
|
|
30
|
+
print(f" ✓ {msg}")
|
|
31
|
+
else:
|
|
32
|
+
failed += 1
|
|
33
|
+
print(f" ✗ {msg}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def main():
|
|
37
|
+
print("=== OpenSandbox Exec API Test (Python) ===\n")
|
|
38
|
+
print(f"API: {API_URL}")
|
|
39
|
+
|
|
40
|
+
# 1. Create sandbox
|
|
41
|
+
print("\n--- 1. Creating sandbox ---")
|
|
42
|
+
sandbox = await Sandbox.create(api_url=API_URL, api_key=API_KEY, template="base")
|
|
43
|
+
print(f" Sandbox: {sandbox.sandbox_id} ({sandbox.status})")
|
|
44
|
+
check(sandbox.status == "running", "sandbox is running")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
# 2. exec.run() — quick command
|
|
48
|
+
print("\n--- 2. exec.run('echo hello world') ---")
|
|
49
|
+
result = await sandbox.exec.run("echo hello world")
|
|
50
|
+
print(f' stdout: "{result.stdout.strip()}"')
|
|
51
|
+
check(result.exit_code == 0, f"exit code is 0 (got {result.exit_code})")
|
|
52
|
+
check(result.stdout.strip() == "hello world", "stdout matches")
|
|
53
|
+
|
|
54
|
+
# 3. exec.run() — ls
|
|
55
|
+
print("\n--- 3. exec.run('ls /') ---")
|
|
56
|
+
ls_result = await sandbox.exec.run("ls /")
|
|
57
|
+
check(ls_result.exit_code == 0, "exit code is 0")
|
|
58
|
+
check("usr" in ls_result.stdout, "stdout contains 'usr'")
|
|
59
|
+
check("bin" in ls_result.stdout, "stdout contains 'bin'")
|
|
60
|
+
|
|
61
|
+
# 4. exec.run() with env vars
|
|
62
|
+
print("\n--- 4. exec.run with env vars ---")
|
|
63
|
+
env_result = await sandbox.exec.run(
|
|
64
|
+
"echo $MY_VAR-$FOO", env={"MY_VAR": "hello", "FOO": "bar"}
|
|
65
|
+
)
|
|
66
|
+
print(f' output: "{env_result.stdout.strip()}"')
|
|
67
|
+
check(env_result.stdout.strip() == "hello-bar", "env vars passed correctly")
|
|
68
|
+
|
|
69
|
+
# 5. exec.run() with cwd
|
|
70
|
+
print("\n--- 5. exec.run('pwd') with cwd=/tmp ---")
|
|
71
|
+
cwd_result = await sandbox.exec.run("pwd", cwd="/tmp")
|
|
72
|
+
print(f' pwd: "{cwd_result.stdout.strip()}"')
|
|
73
|
+
check(cwd_result.stdout.strip() == "/tmp", "cwd is /tmp")
|
|
74
|
+
|
|
75
|
+
# 6. exec.run() — non-zero exit code
|
|
76
|
+
print("\n--- 6. exec.run('exit 42') ---")
|
|
77
|
+
fail_result = await sandbox.exec.run("exit 42")
|
|
78
|
+
print(f" exit: {fail_result.exit_code}")
|
|
79
|
+
check(fail_result.exit_code == 42, f"exit code is 42 (got {fail_result.exit_code})")
|
|
80
|
+
|
|
81
|
+
# 7. exec.run() — stderr
|
|
82
|
+
print("\n--- 7. exec.run stderr ---")
|
|
83
|
+
stderr_result = await sandbox.exec.run("echo error-msg >&2")
|
|
84
|
+
print(f' stderr: "{stderr_result.stderr.strip()}"')
|
|
85
|
+
check(stderr_result.stderr.strip() == "error-msg", "stderr captured")
|
|
86
|
+
|
|
87
|
+
# 8. exec.start() + list + kill
|
|
88
|
+
print("\n--- 8. exec.start('sleep 60') + list + kill ---")
|
|
89
|
+
session_id = await sandbox.exec.start("sleep", args=["60"])
|
|
90
|
+
print(f" session: {session_id}")
|
|
91
|
+
|
|
92
|
+
sessions = await sandbox.exec.list()
|
|
93
|
+
sleep_sessions = [s for s in sessions if s.session_id == session_id]
|
|
94
|
+
check(len(sleep_sessions) == 1, "session appears in list")
|
|
95
|
+
check(sleep_sessions[0].running, "session is running")
|
|
96
|
+
|
|
97
|
+
await sandbox.exec.kill(session_id)
|
|
98
|
+
print(" killed")
|
|
99
|
+
await asyncio.sleep(0.5)
|
|
100
|
+
|
|
101
|
+
sessions_after = await sandbox.exec.list()
|
|
102
|
+
killed = [s for s in sessions_after if s.session_id == session_id]
|
|
103
|
+
if killed:
|
|
104
|
+
check(not killed[0].running, "session is no longer running after kill")
|
|
105
|
+
else:
|
|
106
|
+
check(True, "session cleaned up after kill")
|
|
107
|
+
|
|
108
|
+
# 9. File write + read via exec
|
|
109
|
+
print("\n--- 9. Write file + cat ---")
|
|
110
|
+
await sandbox.files.write("/tmp/test.txt", "Hello from Python SDK!\n")
|
|
111
|
+
cat_result = await sandbox.exec.run("cat /tmp/test.txt")
|
|
112
|
+
print(f' cat: "{cat_result.stdout.strip()}"')
|
|
113
|
+
check(cat_result.stdout.strip() == "Hello from Python SDK!", "file content matches")
|
|
114
|
+
|
|
115
|
+
# 10. Multi-command script
|
|
116
|
+
print("\n--- 10. Multi-command script ---")
|
|
117
|
+
script_result = await sandbox.exec.run(
|
|
118
|
+
"echo hostname=$(hostname); echo user=$(whoami); echo arch=$(uname -m)"
|
|
119
|
+
)
|
|
120
|
+
print(f" {script_result.stdout.strip()}")
|
|
121
|
+
check("hostname=" in script_result.stdout, "has hostname")
|
|
122
|
+
check("user=" in script_result.stdout, "has user")
|
|
123
|
+
|
|
124
|
+
finally:
|
|
125
|
+
# 11. Cleanup
|
|
126
|
+
print("\n--- 11. Killing sandbox ---")
|
|
127
|
+
await sandbox.kill()
|
|
128
|
+
check(sandbox.status == "stopped", "sandbox stopped")
|
|
129
|
+
await sandbox.close()
|
|
130
|
+
|
|
131
|
+
# Summary
|
|
132
|
+
print(f"\n=== Results: {passed} passed, {failed} failed ===")
|
|
133
|
+
if failed > 0:
|
|
134
|
+
raise SystemExit(1)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
asyncio.run(main())
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
"""OpenComputer Python SDK - cloud sandbox platform."""
|
|
2
2
|
|
|
3
3
|
from opencomputer.sandbox import Sandbox
|
|
4
|
+
from opencomputer.agent import Agent, AgentEvent, AgentSession, AgentSessionInfo
|
|
4
5
|
from opencomputer.filesystem import Filesystem
|
|
5
|
-
from opencomputer.
|
|
6
|
+
from opencomputer.exec import Exec, ProcessResult, ExecSessionInfo
|
|
6
7
|
from opencomputer.pty import Pty, PtySession
|
|
7
8
|
from opencomputer.template import Template
|
|
8
9
|
|
|
9
10
|
__all__ = [
|
|
10
11
|
"Sandbox",
|
|
12
|
+
"Agent",
|
|
13
|
+
"AgentEvent",
|
|
14
|
+
"AgentSession",
|
|
15
|
+
"AgentSessionInfo",
|
|
11
16
|
"Filesystem",
|
|
12
|
-
"
|
|
17
|
+
"Exec",
|
|
13
18
|
"ProcessResult",
|
|
19
|
+
"ExecSessionInfo",
|
|
14
20
|
"Pty",
|
|
15
21
|
"PtySession",
|
|
16
22
|
"Template",
|
|
17
23
|
]
|
|
18
24
|
|
|
19
|
-
__version__ = "0.
|
|
25
|
+
__version__ = "0.5.0"
|