axern-sdk 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.
- axern_sdk-0.2.1/.gitignore +51 -0
- axern_sdk-0.2.1/AGENTS.md +75 -0
- axern_sdk-0.2.1/PKG-INFO +373 -0
- axern_sdk-0.2.1/README.md +358 -0
- axern_sdk-0.2.1/examples/_context.py +13 -0
- axern_sdk-0.2.1/examples/async_sandbox_programming.py +54 -0
- axern_sdk-0.2.1/examples/computer_use.py +42 -0
- axern_sdk-0.2.1/examples/function_manifest.py +30 -0
- axern_sdk-0.2.1/examples/sandbox_programming.py +70 -0
- axern_sdk-0.2.1/examples/sandbox_volume.py +41 -0
- axern_sdk-0.2.1/examples/service_gateway.py +142 -0
- axern_sdk-0.2.1/pyproject.toml +31 -0
- axern_sdk-0.2.1/pyrightconfig.json +17 -0
- axern_sdk-0.2.1/scripts/generate_proto.sh +20 -0
- axern_sdk-0.2.1/src/axern/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/common/file/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/common/file/v1/file_pb2.py +43 -0
- axern_sdk-0.2.1/src/axern/common/file/v1/file_pb2.pyi +47 -0
- axern_sdk-0.2.1/src/axern/common/file/v1/file_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/__init__.py +21 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/allocation_lifecycle_pb2.py +62 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/allocation_lifecycle_pb2.pyi +139 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/allocation_lifecycle_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/audit_pb2.py +50 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/audit_pb2.pyi +81 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/audit_pb2_grpc.py +97 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/node_pb2.py +50 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/node_pb2.pyi +72 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/node_pb2_grpc.py +140 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/reliability_pb2.py +80 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/reliability_pb2.pyi +309 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/reliability_pb2_grpc.py +140 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/service_pb2.py +41 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/service_pb2.pyi +19 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/service_pb2_grpc.py +97 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/storage_pb2.py +57 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/storage_pb2.pyi +127 -0
- axern_sdk-0.2.1/src/axern/control/admin/v1/storage_pb2_grpc.py +183 -0
- axern_sdk-0.2.1/src/axern/control/agentprofile/v1/agent_profile_pb2.py +100 -0
- axern_sdk-0.2.1/src/axern/control/agentprofile/v1/agent_profile_pb2.pyi +293 -0
- axern_sdk-0.2.1/src/axern/control/agentprofile/v1/agent_profile_pb2_grpc.py +355 -0
- axern_sdk-0.2.1/src/axern/control/catalog/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/catalog/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/catalog/v1/catalog_pb2.py +81 -0
- axern_sdk-0.2.1/src/axern/control/catalog/v1/catalog_pb2.pyi +203 -0
- axern_sdk-0.2.1/src/axern/control/catalog/v1/catalog_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/common/__init__.py +0 -0
- axern_sdk-0.2.1/src/axern/control/common/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/common/v1/common_pb2.py +85 -0
- axern_sdk-0.2.1/src/axern/control/common/v1/common_pb2.pyi +299 -0
- axern_sdk-0.2.1/src/axern/control/common/v1/common_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/environment/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/environment/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/environment/v1/environment_pb2.py +77 -0
- axern_sdk-0.2.1/src/axern/control/environment/v1/environment_pb2.pyi +164 -0
- axern_sdk-0.2.1/src/axern/control/environment/v1/environment_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/function/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/__init__.py +8 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_pb2.py +85 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_pb2.pyi +203 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_pb2_grpc.py +441 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_types_pb2.py +113 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_types_pb2.pyi +446 -0
- axern_sdk-0.2.1/src/axern/control/function/v1/function_types_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/gateway/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/gateway/v1/gateway_pb2.py +51 -0
- axern_sdk-0.2.1/src/axern/control/gateway/v1/gateway_pb2.pyi +91 -0
- axern_sdk-0.2.1/src/axern/control/gateway/v1/gateway_pb2_grpc.py +140 -0
- axern_sdk-0.2.1/src/axern/control/namespace/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/namespace/v1/namespace_pb2.py +56 -0
- axern_sdk-0.2.1/src/axern/control/namespace/v1/namespace_pb2.pyi +68 -0
- axern_sdk-0.2.1/src/axern/control/namespace/v1/namespace_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/node/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/node/v1/node_control_pb2.py +112 -0
- axern_sdk-0.2.1/src/axern/control/node/v1/node_control_pb2.pyi +520 -0
- axern_sdk-0.2.1/src/axern/control/node/v1/node_control_pb2_grpc.py +312 -0
- axern_sdk-0.2.1/src/axern/control/quota/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/quota/v1/quota_pb2.py +71 -0
- axern_sdk-0.2.1/src/axern/control/quota/v1/quota_pb2.pyi +171 -0
- axern_sdk-0.2.1/src/axern/control/quota/v1/quota_pb2_grpc.py +269 -0
- axern_sdk-0.2.1/src/axern/control/rollout/v1/rollout_pb2.py +165 -0
- axern_sdk-0.2.1/src/axern/control/rollout/v1/rollout_pb2.pyi +745 -0
- axern_sdk-0.2.1/src/axern/control/rollout/v1/rollout_pb2_grpc.py +570 -0
- axern_sdk-0.2.1/src/axern/control/run/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/run/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/run/v1/run_pb2.py +73 -0
- axern_sdk-0.2.1/src/axern/control/run/v1/run_pb2.pyi +156 -0
- axern_sdk-0.2.1/src/axern/control/run/v1/run_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/secret/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/secret/v1/secret_pb2.py +76 -0
- axern_sdk-0.2.1/src/axern/control/secret/v1/secret_pb2.pyi +138 -0
- axern_sdk-0.2.1/src/axern/control/secret/v1/secret_pb2_grpc.py +226 -0
- axern_sdk-0.2.1/src/axern/control/service/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/__init__.py +21 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_event_pb2.py +46 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_event_pb2.pyi +80 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_event_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_pb2.py +74 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_pb2.pyi +144 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_pb2_grpc.py +444 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_replica_pb2.py +55 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_replica_pb2.pyi +124 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_replica_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_types_pb2.py +80 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_types_pb2.pyi +273 -0
- axern_sdk-0.2.1/src/axern/control/service/v1/service_types_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/__init__.py +8 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_pb2.py +87 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_pb2.pyi +181 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_pb2_grpc.py +398 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_types_pb2.py +78 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_types_pb2.pyi +243 -0
- axern_sdk-0.2.1/src/axern/control/storage/v1/storage_types_pb2_grpc.py +24 -0
- axern_sdk-0.2.1/src/axern/control/tunnel/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/control/tunnel/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/control/tunnel/v1/tunnel_pb2.py +83 -0
- axern_sdk-0.2.1/src/axern/control/tunnel/v1/tunnel_pb2.pyi +316 -0
- axern_sdk-0.2.1/src/axern/control/tunnel/v1/tunnel_pb2_grpc.py +398 -0
- axern_sdk-0.2.1/src/axern/data/artifact/v1/artifact_pb2.py +41 -0
- axern_sdk-0.2.1/src/axern/data/artifact/v1/artifact_pb2.pyi +21 -0
- axern_sdk-0.2.1/src/axern/data/artifact/v1/artifact_pb2_grpc.py +97 -0
- axern_sdk-0.2.1/src/axern/node/sandbox/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/node/sandbox/v1/node_pb2.py +220 -0
- axern_sdk-0.2.1/src/axern/node/sandbox/v1/node_pb2.pyi +1019 -0
- axern_sdk-0.2.1/src/axern/node/sandbox/v1/node_pb2_grpc.py +1559 -0
- axern_sdk-0.2.1/src/axern/tunnel/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern/tunnel/v1/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern/tunnel/v1/tunnel_pb2.py +52 -0
- axern_sdk-0.2.1/src/axern/tunnel/v1/tunnel_pb2.pyi +67 -0
- axern_sdk-0.2.1/src/axern/tunnel/v1/tunnel_pb2_grpc.py +97 -0
- axern_sdk-0.2.1/src/axern_sdk/__init__.py +161 -0
- axern_sdk-0.2.1/src/axern_sdk/_internal/__init__.py +1 -0
- axern_sdk-0.2.1/src/axern_sdk/_internal/channel.py +102 -0
- axern_sdk-0.2.1/src/axern_sdk/_internal/errors.py +58 -0
- axern_sdk-0.2.1/src/axern_sdk/_internal/resources.py +80 -0
- axern_sdk-0.2.1/src/axern_sdk/_internal/specs.py +33 -0
- axern_sdk-0.2.1/src/axern_sdk/async_client.py +576 -0
- axern_sdk-0.2.1/src/axern_sdk/catalog/__init__.py +27 -0
- axern_sdk-0.2.1/src/axern_sdk/catalog/client.py +132 -0
- axern_sdk-0.2.1/src/axern_sdk/catalog/models.py +115 -0
- axern_sdk-0.2.1/src/axern_sdk/client.py +641 -0
- axern_sdk-0.2.1/src/axern_sdk/context.py +82 -0
- axern_sdk-0.2.1/src/axern_sdk/errors.py +195 -0
- axern_sdk-0.2.1/src/axern_sdk/function/__init__.py +27 -0
- axern_sdk-0.2.1/src/axern_sdk/function/function.py +410 -0
- axern_sdk-0.2.1/src/axern_sdk/function/manifest.py +324 -0
- axern_sdk-0.2.1/src/axern_sdk/function/models.py +121 -0
- axern_sdk-0.2.1/src/axern_sdk/function/worker.py +380 -0
- axern_sdk-0.2.1/src/axern_sdk/models.py +114 -0
- axern_sdk-0.2.1/src/axern_sdk/node/__init__.py +51 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_browser_client.py +179 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_capability_client.py +42 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_client.py +350 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_computer_use_client.py +150 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_file_client.py +346 -0
- axern_sdk-0.2.1/src/axern_sdk/node/async_process.py +140 -0
- axern_sdk-0.2.1/src/axern_sdk/node/browser_client.py +179 -0
- axern_sdk-0.2.1/src/axern_sdk/node/capability_client.py +42 -0
- axern_sdk-0.2.1/src/axern_sdk/node/capability_protocol.py +49 -0
- axern_sdk-0.2.1/src/axern_sdk/node/client.py +315 -0
- axern_sdk-0.2.1/src/axern_sdk/node/commands.py +35 -0
- axern_sdk-0.2.1/src/axern_sdk/node/computer_use_client.py +150 -0
- axern_sdk-0.2.1/src/axern_sdk/node/computer_use_protocol.py +72 -0
- axern_sdk-0.2.1/src/axern_sdk/node/file_client.py +346 -0
- axern_sdk-0.2.1/src/axern_sdk/node/models.py +208 -0
- axern_sdk-0.2.1/src/axern_sdk/node/process.py +155 -0
- axern_sdk-0.2.1/src/axern_sdk/node/protocol.py +126 -0
- axern_sdk-0.2.1/src/axern_sdk/py.typed +1 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/__init__.py +48 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/archive.py +140 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_browser.py +63 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_capabilities.py +18 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_computer_use.py +88 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_files.py +244 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_lifecycle.py +86 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_renewal.py +77 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/async_sandbox.py +474 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/browser.py +57 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/capabilities.py +18 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/computer_use.py +88 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/files.py +242 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/lifecycle.py +79 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/renewal.py +84 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/sandbox.py +474 -0
- axern_sdk-0.2.1/src/axern_sdk/sandbox/types.py +45 -0
- axern_sdk-0.2.1/src/axern_sdk/tunnel/__init__.py +6 -0
- axern_sdk-0.2.1/src/axern_sdk/tunnel/config.py +27 -0
- axern_sdk-0.2.1/src/axern_sdk/tunnel/connector.py +131 -0
- axern_sdk-0.2.1/src/axern_sdk/tunnel/frames.py +31 -0
- axern_sdk-0.2.1/src/axern_sdk/tunnel/streams.py +134 -0
- axern_sdk-0.2.1/tests/e2e/computer_use_e2e.py +458 -0
- axern_sdk-0.2.1/tests/e2e/python_runtime_e2e.py +84 -0
- axern_sdk-0.2.1/tests/e2e/sandbox_tunnel_e2e.py +302 -0
- axern_sdk-0.2.1/tests/fakes.py +152 -0
- axern_sdk-0.2.1/tests/test_admin_service.py +83 -0
- axern_sdk-0.2.1/tests/test_catalog.py +111 -0
- axern_sdk-0.2.1/tests/test_context.py +63 -0
- axern_sdk-0.2.1/tests/test_contract_v1.py +161 -0
- axern_sdk-0.2.1/tests/test_function_manifest.py +335 -0
- axern_sdk-0.2.1/tests/test_function_worker.py +99 -0
- axern_sdk-0.2.1/tests/test_node_client.py +450 -0
- axern_sdk-0.2.1/tests/test_sandbox_exec.py +408 -0
- axern_sdk-0.2.1/tests/test_sandbox_files.py +569 -0
- axern_sdk-0.2.1/tests/test_sandbox_lifecycle.py +420 -0
- axern_sdk-0.2.1/tests/test_service_watch.py +272 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Environment
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
/work/
|
|
6
|
+
|
|
7
|
+
# Common build outputs
|
|
8
|
+
/bin/
|
|
9
|
+
/.axrun/
|
|
10
|
+
dist/
|
|
11
|
+
target/
|
|
12
|
+
build/
|
|
13
|
+
out/
|
|
14
|
+
coverage/
|
|
15
|
+
!runtime/axnoded/build/
|
|
16
|
+
!runtime/axnoded/build/executable/
|
|
17
|
+
!runtime/axnoded/build/executable/**
|
|
18
|
+
runtime/axnoded/executable
|
|
19
|
+
|
|
20
|
+
# Node / TypeScript
|
|
21
|
+
node_modules/
|
|
22
|
+
/apps/docs/.astro/
|
|
23
|
+
.pnpm-debug.log*
|
|
24
|
+
pnpm-debug.log*
|
|
25
|
+
*.tsbuildinfo
|
|
26
|
+
|
|
27
|
+
# Go
|
|
28
|
+
*.exe
|
|
29
|
+
*.dll
|
|
30
|
+
*.so
|
|
31
|
+
*.dylib
|
|
32
|
+
*.test
|
|
33
|
+
*.prof
|
|
34
|
+
__debug_bin*
|
|
35
|
+
gateway/gatewayd/internal/api/http/dashboard/vendor/*
|
|
36
|
+
!gateway/gatewayd/internal/api/http/dashboard/vendor/.gitkeep
|
|
37
|
+
|
|
38
|
+
# Python
|
|
39
|
+
.venv/
|
|
40
|
+
__pycache__/
|
|
41
|
+
*.py[cod]
|
|
42
|
+
.pytest_cache/
|
|
43
|
+
.mypy_cache/
|
|
44
|
+
.ruff_cache/
|
|
45
|
+
|
|
46
|
+
# OS / editors
|
|
47
|
+
.DS_Store
|
|
48
|
+
Thumbs.db
|
|
49
|
+
.idea/
|
|
50
|
+
*.iml
|
|
51
|
+
.dev/
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Local contract for the Axern Python SDK workspace. Follow the root
|
|
6
|
+
[`../../AGENTS.md`](../../AGENTS.md) first, then apply this file under
|
|
7
|
+
`sdk/python`.
|
|
8
|
+
|
|
9
|
+
## Workspace Boundaries
|
|
10
|
+
|
|
11
|
+
- Keep importable code under [`src`](src), generated protobuf modules under
|
|
12
|
+
[`src/axern`](src/axern), and user-facing SDK code under
|
|
13
|
+
[`src/axern_sdk`](src/axern_sdk).
|
|
14
|
+
- Keep tests under [`tests`](tests).
|
|
15
|
+
- Do not add product apps, demos, services, or platform entrypoints here.
|
|
16
|
+
|
|
17
|
+
## API And Structure
|
|
18
|
+
|
|
19
|
+
- Treat `axern_sdk.__init__`, `client`, `catalog`, `sandbox`, and `tunnel` as
|
|
20
|
+
public API boundaries; keep exports intentional and small.
|
|
21
|
+
- Do not add compatibility aliases for flawed early API shapes unless a concrete
|
|
22
|
+
external contract requires them.
|
|
23
|
+
- Prefer explicit source models over inferred defaults. Environment and sandbox
|
|
24
|
+
callers should provide exactly one source: `template_id`, `image`, or
|
|
25
|
+
`environment_id`.
|
|
26
|
+
- Keep files cohesive by responsibility. Do not grow orchestration files into
|
|
27
|
+
mixed client, lifecycle, transport, and model implementations.
|
|
28
|
+
- Put private shared helpers in `axern_sdk._internal` when they are not part of
|
|
29
|
+
the SDK surface.
|
|
30
|
+
- Do not hand-edit generated `*_pb2.py` or `*_pb2_grpc.py` files.
|
|
31
|
+
|
|
32
|
+
## Proto Generation
|
|
33
|
+
|
|
34
|
+
- Regenerate Python protobuf modules with
|
|
35
|
+
[`scripts/generate_proto.sh`](scripts/generate_proto.sh).
|
|
36
|
+
- When adding proto dependencies, update the generation script, required
|
|
37
|
+
generated `__init__.py` files, [`pyproject.toml`](pyproject.toml), and
|
|
38
|
+
[`../../uv.lock`](../../uv.lock) together.
|
|
39
|
+
|
|
40
|
+
## Sandbox And Tunnel Rules
|
|
41
|
+
|
|
42
|
+
- `Sandbox` owns SDK-created environment, service, tunnel session, connector,
|
|
43
|
+
renewal, and cleanup lifecycle.
|
|
44
|
+
- Long-lived tunnel support must renew finite tunnel TTLs automatically.
|
|
45
|
+
- Cleanup is best-effort and must not mask startup failures or wait too long
|
|
46
|
+
after an earlier cleanup step failed.
|
|
47
|
+
- Tunnel framing, renewal, cleanup, or readiness changes need focused unit tests
|
|
48
|
+
and compose SDK e2e validation.
|
|
49
|
+
|
|
50
|
+
## Validation
|
|
51
|
+
|
|
52
|
+
- Python SDK code:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
make test-py
|
|
56
|
+
make lint-py
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Package metadata, generated proto, dependency, or distribution changes:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv build sdk/python
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `Sandbox`, tunnel, cleanup, service lifecycle, or compose workflow changes:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
make local-compose-python-sdk-e2e
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- This file or repo-local documentation:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
make agent-doc-check
|
|
75
|
+
```
|
axern_sdk-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: axern-sdk
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Python SDK for Axern agentic infrastructure and isolated sandboxes
|
|
5
|
+
Project-URL: Homepage, https://axern.cofy-x.space/sdk/python/
|
|
6
|
+
Project-URL: Documentation, https://axern.cofy-x.space/sdk/python/
|
|
7
|
+
Project-URL: Repository, https://github.com/cofy-x/axern
|
|
8
|
+
Project-URL: Issues, https://github.com/cofy-x/axern/issues
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: grpcio>=1.81.0
|
|
12
|
+
Requires-Dist: protobuf>=6.31.1
|
|
13
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# Axern Python SDK
|
|
17
|
+
|
|
18
|
+
The Axern Python SDK is the first-class programmable interface for Axern
|
|
19
|
+
sandboxes. It exposes both the control plane client and a high-level
|
|
20
|
+
`Sandbox` API for lifecycle, command execution, attached processes, file
|
|
21
|
+
operations, directory transfer, tunnels, capability discovery, and diagnostics.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
Install the published package:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv add axern-sdk
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For repository development, build and run examples through the root `uv`
|
|
32
|
+
workspace:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv build --no-sources sdk/python
|
|
36
|
+
uv run --package axern-sdk python sdk/python/examples/sandbox_programming.py
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Connect
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from axern_sdk import AxernClient
|
|
43
|
+
|
|
44
|
+
client = AxernClient.from_context("~/.config/axern/config.json")
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
TLS-enabled local compose setups can pass certificate paths directly:
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
client = AxernClient(
|
|
51
|
+
"127.0.0.1:25000",
|
|
52
|
+
tls_ca_cert=".dev/certs/ca.crt",
|
|
53
|
+
tls_cert=".dev/certs/client.crt",
|
|
54
|
+
tls_key=".dev/certs/client.key",
|
|
55
|
+
)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`AsyncAxernClient` provides the same control-plane surface for asyncio code.
|
|
59
|
+
Constructors are explicit and never read the user directory. `from_context()`
|
|
60
|
+
loads a named CLI context from the supplied path; `from_env()` is available for
|
|
61
|
+
environment-driven automation and reads `AXERN_ENDPOINT` plus the gateway TLS
|
|
62
|
+
and proxy variables.
|
|
63
|
+
|
|
64
|
+
## Sandbox Sources
|
|
65
|
+
|
|
66
|
+
Create a sandbox from exactly one source:
|
|
67
|
+
|
|
68
|
+
- `template_id="python311"` for a catalog template.
|
|
69
|
+
- `image="docker.io/library/python:3.12-slim"` for an OCI image.
|
|
70
|
+
- `environment_id="..."` for an existing environment.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from axern_sdk import AxernClient, Sandbox
|
|
74
|
+
|
|
75
|
+
client = AxernClient("127.0.0.1:25000")
|
|
76
|
+
|
|
77
|
+
with Sandbox(client=client, template_id="python311") as sandbox:
|
|
78
|
+
print(sandbox.metadata.allocation_id)
|
|
79
|
+
|
|
80
|
+
client.close()
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Volumes
|
|
84
|
+
|
|
85
|
+
Use `VolumeMount` to attach Service V1 volumes to service-backed sandboxes.
|
|
86
|
+
The SDK passes volume intent through the public control plane; storage
|
|
87
|
+
resolution, node publish, mount injection, and release remain owned by Axern's
|
|
88
|
+
Storage V1 runtime flow.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from axern_sdk import Sandbox, VolumeMount
|
|
92
|
+
|
|
93
|
+
with Sandbox(
|
|
94
|
+
client=client,
|
|
95
|
+
template_id="python311",
|
|
96
|
+
volumes=[
|
|
97
|
+
VolumeMount("data", "/data"),
|
|
98
|
+
VolumeMount("cache", "/cache", readonly=True, options=("rbind",)),
|
|
99
|
+
],
|
|
100
|
+
) as sandbox:
|
|
101
|
+
result = sandbox.exec("ls /data /cache", text=True, check=True)
|
|
102
|
+
print(result.stdout)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Function Manifests
|
|
106
|
+
|
|
107
|
+
`Function.from_file()` loads and validates an `axern/v1` Function resource.
|
|
108
|
+
`Function.package()` creates a deterministic tar bundle, and `Function.deploy()`
|
|
109
|
+
packages the source, uploads it with `FunctionControl.UploadFunctionBundle`,
|
|
110
|
+
and then calls `FunctionControl.DeployFunction`. The `python311` runtime image
|
|
111
|
+
includes the SDK Function worker module used by controld-managed warm workers.
|
|
112
|
+
`Function.invoke()` calls the dedicated Function invocation API and returns a
|
|
113
|
+
decoded invocation result.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from axern_sdk import AxernClient, Function
|
|
117
|
+
|
|
118
|
+
client = AxernClient.from_context("~/.config/axern/config.json")
|
|
119
|
+
function = Function.from_file(client, "examples/function-hello/function.yaml")
|
|
120
|
+
deployment = function.deploy(labels={"team": "runtime"})
|
|
121
|
+
|
|
122
|
+
print(function.name)
|
|
123
|
+
print(function.spec.handler)
|
|
124
|
+
print(deployment.function.id)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Exec
|
|
128
|
+
|
|
129
|
+
Use `exec()` for command-result workflows. Set `text=True` to decode stdout and
|
|
130
|
+
stderr; set `check=True` to raise `SandboxExecError` on non-zero exit.
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
with Sandbox(client=client, template_id="python311") as sandbox:
|
|
134
|
+
result = sandbox.exec("python -c \"print('hello')\"", text=True, check=True)
|
|
135
|
+
print(result.stdout)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Use `exec_stream()` when stdout/stderr should be consumed as events:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
for event in sandbox.exec_stream(["python", "-u", "-c", "print('streamed')"]):
|
|
142
|
+
if event.stream == "stdout":
|
|
143
|
+
print(event.text(), end="")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Attached Process
|
|
147
|
+
|
|
148
|
+
Use `process()` when your program needs to control stdin, observe output, wait,
|
|
149
|
+
or terminate a running command.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
with sandbox.process(["python", "-u", "-c", "import sys; print(sys.stdin.read().upper())"]) as process:
|
|
153
|
+
process.write("hello process\n")
|
|
154
|
+
process.close_stdin()
|
|
155
|
+
|
|
156
|
+
for event in process.events():
|
|
157
|
+
if event.stream == "stdout":
|
|
158
|
+
print(event.text(), end="")
|
|
159
|
+
|
|
160
|
+
result = process.wait()
|
|
161
|
+
print(result.exit_code)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`AsyncSandbox.process()` returns `AsyncSandboxProcess` with async equivalents of
|
|
165
|
+
`write()`, `close_stdin()`, `events()`, `wait()`, `terminate()`, and `kill()`.
|
|
166
|
+
|
|
167
|
+
## Image-Backed Processes
|
|
168
|
+
|
|
169
|
+
Use `exec_image()` or `process_image()` to run a tool from a separate image
|
|
170
|
+
against explicit host-backed sandbox paths. OCI and Nydus image refs use the
|
|
171
|
+
same `image` field. When `mounts=None`, the SDK requests `/workspace ->
|
|
172
|
+
/workspace`; pass `mounts=[]` for no shared paths. Use `Sandbox(image=...)`
|
|
173
|
+
when the image should be the sandbox rootfs with normal files, exec, process,
|
|
174
|
+
tunnel, and lifecycle APIs; image-backed processes are temporary side processes
|
|
175
|
+
attached to an existing sandbox.
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from axern_sdk import workspace_mount
|
|
179
|
+
|
|
180
|
+
result = sandbox.exec_image(
|
|
181
|
+
"ghcr.io/cofy-x/agent:latest",
|
|
182
|
+
"tool run",
|
|
183
|
+
mounts=[workspace_mount("/workspace")],
|
|
184
|
+
check=True,
|
|
185
|
+
text=True,
|
|
186
|
+
)
|
|
187
|
+
print(result.stdout)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Files
|
|
191
|
+
|
|
192
|
+
Single-file APIs are byte-safe. Text helpers only encode/decode at the SDK
|
|
193
|
+
boundary.
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
sandbox.write_text("/tmp/message.txt", "payload\n")
|
|
197
|
+
print(sandbox.read_text("/tmp/message.txt"))
|
|
198
|
+
|
|
199
|
+
sandbox.write_bytes("/tmp/blob.bin", b"\x00\x01")
|
|
200
|
+
data = sandbox.read_bytes("/tmp/blob.bin")
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Platform file operations are handled by the node/runtime file service, not by
|
|
204
|
+
SDK-side shell fallbacks:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
sandbox.copy("/tmp/message.txt", "/tmp/message-copy.txt", overwrite=True)
|
|
208
|
+
sandbox.move("/tmp/message-copy.txt", "/tmp/message-final.txt")
|
|
209
|
+
sandbox.chmod("/tmp/message-final.txt", 0o600)
|
|
210
|
+
sandbox.touch("/tmp/message-final.txt")
|
|
211
|
+
|
|
212
|
+
info = sandbox.stat("/tmp/message-final.txt")
|
|
213
|
+
entries = sandbox.list_dir("/tmp")
|
|
214
|
+
exists = sandbox.exists("/tmp/message-final.txt")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Directory Transfer
|
|
218
|
+
|
|
219
|
+
Directory upload/download uses archive streaming. The SDK packages local
|
|
220
|
+
directories with `tarfile` and safely extracts downloaded archives; remote file
|
|
221
|
+
semantics remain owned by the platform file service.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from pathlib import Path
|
|
225
|
+
|
|
226
|
+
source = Path("example-upload")
|
|
227
|
+
source.mkdir(exist_ok=True)
|
|
228
|
+
source.joinpath("data.txt").write_text("directory payload\n")
|
|
229
|
+
|
|
230
|
+
sandbox.upload_dir(source, "/tmp/example-upload", overwrite=True)
|
|
231
|
+
sandbox.download_dir("/tmp/example-upload", "example-download", overwrite=True)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Local symlinks are rejected during upload. Download extraction rejects absolute
|
|
235
|
+
paths, parent traversal, symlinks, and hardlinks.
|
|
236
|
+
|
|
237
|
+
## Tunnel
|
|
238
|
+
|
|
239
|
+
Pass `upstream` to expose a local TCP service to code running inside the
|
|
240
|
+
sandbox. The SDK owns the tunnel connector and renews finite tunnel TTLs while
|
|
241
|
+
the sandbox is active.
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
from axern_sdk import Sandbox
|
|
245
|
+
|
|
246
|
+
with Sandbox(
|
|
247
|
+
client=client,
|
|
248
|
+
image="docker.io/library/python:3.12-slim",
|
|
249
|
+
upstream="127.0.0.1:8080",
|
|
250
|
+
remote_port=8786,
|
|
251
|
+
) as sandbox:
|
|
252
|
+
print(sandbox.bound_addr)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Metadata
|
|
256
|
+
|
|
257
|
+
`Sandbox.state` is the lightweight runtime state. `Sandbox.metadata` is stable
|
|
258
|
+
for logs and diagnostics:
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
metadata = sandbox.metadata
|
|
262
|
+
print(metadata.environment_id, metadata.service_id, metadata.allocation_id)
|
|
263
|
+
print(metadata.node_id, metadata.runtime_class, metadata.tunnel_session_id)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Capabilities
|
|
267
|
+
|
|
268
|
+
Use `capability_status()` to discover baseline and optional sandboxd-backed
|
|
269
|
+
providers before calling desktop or browser APIs:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
status = sandbox.capability_status()
|
|
273
|
+
print(status.ready, status.capabilities)
|
|
274
|
+
|
|
275
|
+
for provider in status.providers:
|
|
276
|
+
print(provider.name, provider.state, provider.available, provider.reason)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Errors
|
|
280
|
+
|
|
281
|
+
SDK exceptions expose fields for programmatic handling:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
from axern_sdk import (
|
|
285
|
+
SandboxConnectionError,
|
|
286
|
+
SandboxPermissionError,
|
|
287
|
+
SandboxPreconditionError,
|
|
288
|
+
SandboxRpcError,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
sandbox.exec("python -V", check=True)
|
|
293
|
+
except SandboxConnectionError as exc:
|
|
294
|
+
if exc.retryable:
|
|
295
|
+
print("temporary node/control-plane connectivity issue")
|
|
296
|
+
raise
|
|
297
|
+
except SandboxPermissionError as exc:
|
|
298
|
+
print("credentials do not permit this operation", exc.operation)
|
|
299
|
+
raise
|
|
300
|
+
except SandboxPreconditionError as exc:
|
|
301
|
+
if exc.capability:
|
|
302
|
+
print(
|
|
303
|
+
exc.capability.capability,
|
|
304
|
+
exc.capability.provider,
|
|
305
|
+
exc.capability.provider_state,
|
|
306
|
+
exc.capability.missing_dependencies,
|
|
307
|
+
)
|
|
308
|
+
raise
|
|
309
|
+
except SandboxRpcError as exc:
|
|
310
|
+
print(exc.operation, exc.code, exc.details, exc.allocation_id)
|
|
311
|
+
raise
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Common error classes:
|
|
315
|
+
|
|
316
|
+
- `SandboxNotStartedError`: operation requires an active sandbox.
|
|
317
|
+
- `SandboxExecError`: `exec(..., check=True)` observed non-zero exit.
|
|
318
|
+
- `SandboxConnectionError`: transport or connectivity failure.
|
|
319
|
+
- `SandboxPermissionError`: authentication or authorization failure.
|
|
320
|
+
- `SandboxRpcError`: gRPC status mapped from node/runtime APIs.
|
|
321
|
+
- `SandboxTimeoutError`: SDK-side timeout.
|
|
322
|
+
|
|
323
|
+
Sandboxd-backed capability failures keep their normal SDK exception class and
|
|
324
|
+
also expose `exc.capability` when the node returns provider diagnostics. That
|
|
325
|
+
object contains `capability`, `provider`, `provider_state`, `reason`, and
|
|
326
|
+
`missing_dependencies`, so callers can branch on missing browser or
|
|
327
|
+
computer-use dependencies without parsing the full error string.
|
|
328
|
+
|
|
329
|
+
## Async
|
|
330
|
+
|
|
331
|
+
Async APIs mirror the synchronous shape:
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
from axern_sdk import AsyncAxernClient, AsyncSandbox
|
|
335
|
+
|
|
336
|
+
async with AsyncAxernClient("127.0.0.1:25000") as client:
|
|
337
|
+
async with AsyncSandbox(client=client, template_id="python311") as sandbox:
|
|
338
|
+
result = await sandbox.exec("python -c \"print('hello async')\"", text=True, check=True)
|
|
339
|
+
print(result.stdout)
|
|
340
|
+
|
|
341
|
+
async with await sandbox.process(["python", "-u", "-c", "import sys; print(sys.stdin.read())"]) as process:
|
|
342
|
+
await process.write("async input\n")
|
|
343
|
+
await process.close_stdin()
|
|
344
|
+
async for event in process.events():
|
|
345
|
+
if event.stream == "stdout":
|
|
346
|
+
print(event.text(), end="")
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Examples
|
|
350
|
+
|
|
351
|
+
Runnable examples live in [`examples`](examples):
|
|
352
|
+
|
|
353
|
+
- [`examples/function_manifest.py`](examples/function_manifest.py)
|
|
354
|
+
- [`examples/sandbox_programming.py`](examples/sandbox_programming.py)
|
|
355
|
+
- [`examples/sandbox_volume.py`](examples/sandbox_volume.py)
|
|
356
|
+
- [`examples/async_sandbox_programming.py`](examples/async_sandbox_programming.py)
|
|
357
|
+
- [`examples/computer_use.py`](examples/computer_use.py)
|
|
358
|
+
- [`examples/service_gateway.py`](examples/service_gateway.py)
|
|
359
|
+
|
|
360
|
+
Examples expect a reachable Axern gateway control edge at `127.0.0.1:25000`.
|
|
361
|
+
`service_gateway.py` also expects `AXERN_SERVICE_URL`, for example
|
|
362
|
+
`http://127.0.0.1:25080`. It accepts `AXERN_NAMESPACE`, `AXERN_TEMPLATE_ID`,
|
|
363
|
+
`AXERN_RUNTIME_CLASS`, `AXERN_REQUEST_CPU`, `AXERN_REQUEST_MEMORY`,
|
|
364
|
+
`AXERN_LIMIT_CPU`, and `AXERN_LIMIT_MEMORY` for service configuration.
|
|
365
|
+
|
|
366
|
+
## Validation
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
make test-py
|
|
370
|
+
make lint-py
|
|
371
|
+
make sdk-python-verify
|
|
372
|
+
make local-compose-python-sdk-e2e
|
|
373
|
+
```
|