islo 0.1.0__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.
- islo-0.1.0/PKG-INFO +82 -0
- islo-0.1.0/README.md +59 -0
- islo-0.1.0/islo/__init__.py +26 -0
- islo-0.1.0/islo/_api/__init__.py +0 -0
- islo-0.1.0/islo/_api/auth.py +19 -0
- islo-0.1.0/islo/_api/certificate_authority.py +30 -0
- islo-0.1.0/islo/_api/integrations.py +46 -0
- islo-0.1.0/islo/_api/models_.py +18 -0
- islo-0.1.0/islo/_api/sandboxes.py +256 -0
- islo-0.1.0/islo/_api/shares.py +39 -0
- islo-0.1.0/islo/_api/tenants.py +56 -0
- islo-0.1.0/islo/_api/usage.py +31 -0
- islo-0.1.0/islo/_api/users.py +46 -0
- islo-0.1.0/islo/_base.py +96 -0
- islo-0.1.0/islo/_client.py +133 -0
- islo-0.1.0/islo/_exceptions.py +46 -0
- islo-0.1.0/islo/models.py +398 -0
- islo-0.1.0/islo/py.typed +0 -0
- islo-0.1.0/pyproject.toml +55 -0
islo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: islo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Typed Python SDK for the Islo Web API
|
|
5
|
+
Keywords: islo,sdk,openapi,api-client
|
|
6
|
+
Author: Islo Labs
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: httpx>=0.23.0,<0.29.0
|
|
17
|
+
Requires-Dist: pydantic[email]>=2.0.0
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Project-URL: Homepage, https://github.com/islo-labs/islo-sdk
|
|
20
|
+
Project-URL: Repository, https://github.com/islo-labs/islo-sdk
|
|
21
|
+
Project-URL: Issues, https://github.com/islo-labs/islo-sdk/issues
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# islo
|
|
25
|
+
|
|
26
|
+
Typed Python SDK for the [Islo](https://islo.dev) API.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pip install islo
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from islo import Islo
|
|
38
|
+
|
|
39
|
+
client = Islo(api_key="sk-...")
|
|
40
|
+
|
|
41
|
+
# List sandboxes
|
|
42
|
+
sandboxes = client.sandboxes.list(limit=20)
|
|
43
|
+
|
|
44
|
+
# Create a sandbox
|
|
45
|
+
from islo.models import SandboxCreate, SandboxSpec
|
|
46
|
+
|
|
47
|
+
sandbox = client.sandboxes.create(body=SandboxCreate(
|
|
48
|
+
name="my-sandbox",
|
|
49
|
+
spec=SandboxSpec(cpu=2, memory=4096),
|
|
50
|
+
))
|
|
51
|
+
|
|
52
|
+
# Get a sandbox
|
|
53
|
+
sandbox = client.sandboxes.get("my-sandbox")
|
|
54
|
+
|
|
55
|
+
# Execute a command
|
|
56
|
+
from islo.models import ExecRequest
|
|
57
|
+
|
|
58
|
+
result = client.sandboxes.exec("my-sandbox", body=ExecRequest(
|
|
59
|
+
command=["echo", "hello"],
|
|
60
|
+
))
|
|
61
|
+
|
|
62
|
+
# Delete
|
|
63
|
+
client.sandboxes.delete("my-sandbox")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Resources
|
|
67
|
+
|
|
68
|
+
| Resource | Methods |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `client.sandboxes` | `list`, `create`, `get`, `delete`, `stop`, `exec`, `exec_stream`, `promote_cache`, `list_agent_sessions`, `get_agent_session_events`, `list_exec_sessions`, `get_exec_session_logs` |
|
|
71
|
+
| `client.tenants` | `list`, `create`, `get_settings`, `update_settings`, `get_subscription` |
|
|
72
|
+
| `client.users` | `get`, `invite`, `update`, `authorize` |
|
|
73
|
+
| `client.shares` | `list`, `create`, `revoke` |
|
|
74
|
+
| `client.integrations` | `list`, `list_providers`, `get_status`, `disconnect` |
|
|
75
|
+
| `client.usage` | `sandbox_usage`, `summary` |
|
|
76
|
+
| `client.certificate_authority` | `create_certificate`, `get_public_key` |
|
|
77
|
+
|
|
78
|
+
## Regenerate
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
just sync
|
|
82
|
+
```
|
islo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# islo
|
|
2
|
+
|
|
3
|
+
Typed Python SDK for the [Islo](https://islo.dev) API.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pip install islo
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from islo import Islo
|
|
15
|
+
|
|
16
|
+
client = Islo(api_key="sk-...")
|
|
17
|
+
|
|
18
|
+
# List sandboxes
|
|
19
|
+
sandboxes = client.sandboxes.list(limit=20)
|
|
20
|
+
|
|
21
|
+
# Create a sandbox
|
|
22
|
+
from islo.models import SandboxCreate, SandboxSpec
|
|
23
|
+
|
|
24
|
+
sandbox = client.sandboxes.create(body=SandboxCreate(
|
|
25
|
+
name="my-sandbox",
|
|
26
|
+
spec=SandboxSpec(cpu=2, memory=4096),
|
|
27
|
+
))
|
|
28
|
+
|
|
29
|
+
# Get a sandbox
|
|
30
|
+
sandbox = client.sandboxes.get("my-sandbox")
|
|
31
|
+
|
|
32
|
+
# Execute a command
|
|
33
|
+
from islo.models import ExecRequest
|
|
34
|
+
|
|
35
|
+
result = client.sandboxes.exec("my-sandbox", body=ExecRequest(
|
|
36
|
+
command=["echo", "hello"],
|
|
37
|
+
))
|
|
38
|
+
|
|
39
|
+
# Delete
|
|
40
|
+
client.sandboxes.delete("my-sandbox")
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Resources
|
|
44
|
+
|
|
45
|
+
| Resource | Methods |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `client.sandboxes` | `list`, `create`, `get`, `delete`, `stop`, `exec`, `exec_stream`, `promote_cache`, `list_agent_sessions`, `get_agent_session_events`, `list_exec_sessions`, `get_exec_session_logs` |
|
|
48
|
+
| `client.tenants` | `list`, `create`, `get_settings`, `update_settings`, `get_subscription` |
|
|
49
|
+
| `client.users` | `get`, `invite`, `update`, `authorize` |
|
|
50
|
+
| `client.shares` | `list`, `create`, `revoke` |
|
|
51
|
+
| `client.integrations` | `list`, `list_providers`, `get_status`, `disconnect` |
|
|
52
|
+
| `client.usage` | `sandbox_usage`, `summary` |
|
|
53
|
+
| `client.certificate_authority` | `create_certificate`, `get_public_key` |
|
|
54
|
+
|
|
55
|
+
## Regenerate
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
just sync
|
|
59
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Islo Python SDK."""
|
|
2
|
+
|
|
3
|
+
from islo._client import AsyncIslo, Islo
|
|
4
|
+
from islo._exceptions import (
|
|
5
|
+
APIStatusError,
|
|
6
|
+
AuthenticationError,
|
|
7
|
+
InternalServerError,
|
|
8
|
+
IsloError,
|
|
9
|
+
NotFoundError,
|
|
10
|
+
PermissionDeniedError,
|
|
11
|
+
RateLimitError,
|
|
12
|
+
UnprocessableEntityError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"AsyncIslo",
|
|
17
|
+
"Islo",
|
|
18
|
+
"IsloError",
|
|
19
|
+
"APIStatusError",
|
|
20
|
+
"AuthenticationError",
|
|
21
|
+
"PermissionDeniedError",
|
|
22
|
+
"NotFoundError",
|
|
23
|
+
"UnprocessableEntityError",
|
|
24
|
+
"RateLimitError",
|
|
25
|
+
"InternalServerError",
|
|
26
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
4
|
+
from islo.models import (
|
|
5
|
+
TokenRequest,
|
|
6
|
+
TokenResponse,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Auth(SyncAPIResource):
|
|
11
|
+
def exchange_token(self, *, body: TokenRequest) -> TokenResponse:
|
|
12
|
+
"""Exchange an access key for a session token."""
|
|
13
|
+
return self._request("POST", "/auth/token", json_body=body, response_model=TokenResponse)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AsyncAuth(AsyncAPIResource):
|
|
17
|
+
async def exchange_token(self, *, body: TokenRequest) -> TokenResponse:
|
|
18
|
+
"""Exchange an access key for a session token."""
|
|
19
|
+
return await self._request("POST", "/auth/token", json_body=body, response_model=TokenResponse)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
4
|
+
from islo.models import (
|
|
5
|
+
CAPublicKeyResponse,
|
|
6
|
+
SSHCertificateRequest,
|
|
7
|
+
SSHCertificateResponse,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CertificateAuthority(SyncAPIResource):
|
|
12
|
+
def create_certificate(self, *, body: SSHCertificateRequest) -> SSHCertificateResponse:
|
|
13
|
+
"""Issue SSH certificate"""
|
|
14
|
+
return self._request("POST", "/certificate-authority/", json_body=body, response_model=SSHCertificateResponse)
|
|
15
|
+
|
|
16
|
+
def get_public_key(self) -> CAPublicKeyResponse:
|
|
17
|
+
"""Get CA public key"""
|
|
18
|
+
return self._request("GET", "/certificate-authority/public-key", response_model=CAPublicKeyResponse)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AsyncCertificateAuthority(AsyncAPIResource):
|
|
22
|
+
async def create_certificate(self, *, body: SSHCertificateRequest) -> SSHCertificateResponse:
|
|
23
|
+
"""Issue SSH certificate"""
|
|
24
|
+
return await self._request(
|
|
25
|
+
"POST", "/certificate-authority/", json_body=body, response_model=SSHCertificateResponse
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
async def get_public_key(self) -> CAPublicKeyResponse:
|
|
29
|
+
"""Get CA public key"""
|
|
30
|
+
return await self._request("GET", "/certificate-authority/public-key", response_model=CAPublicKeyResponse)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
6
|
+
from islo.models import (
|
|
7
|
+
IntegrationDetailResponse,
|
|
8
|
+
IntegrationListResponse,
|
|
9
|
+
IntegrationProvidersResponse,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Integrations(SyncAPIResource):
|
|
14
|
+
def list(self) -> IntegrationListResponse:
|
|
15
|
+
"""List User Integrations"""
|
|
16
|
+
return self._request("GET", "/integrations", response_model=IntegrationListResponse)
|
|
17
|
+
|
|
18
|
+
def list_providers(self) -> IntegrationProvidersResponse:
|
|
19
|
+
"""List Providers"""
|
|
20
|
+
return self._request("GET", "/integrations/providers", response_model=IntegrationProvidersResponse)
|
|
21
|
+
|
|
22
|
+
def disconnect(self, provider: str, *, level: str | None = "user") -> Any:
|
|
23
|
+
"""Disconnect Integration"""
|
|
24
|
+
return self._request("DELETE", f"/integrations/{provider}", params={"level": level})
|
|
25
|
+
|
|
26
|
+
def get_status(self, provider: str) -> IntegrationDetailResponse:
|
|
27
|
+
"""Get Integration Status"""
|
|
28
|
+
return self._request("GET", f"/integrations/{provider}", response_model=IntegrationDetailResponse)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AsyncIntegrations(AsyncAPIResource):
|
|
32
|
+
async def list(self) -> IntegrationListResponse:
|
|
33
|
+
"""List User Integrations"""
|
|
34
|
+
return await self._request("GET", "/integrations", response_model=IntegrationListResponse)
|
|
35
|
+
|
|
36
|
+
async def list_providers(self) -> IntegrationProvidersResponse:
|
|
37
|
+
"""List Providers"""
|
|
38
|
+
return await self._request("GET", "/integrations/providers", response_model=IntegrationProvidersResponse)
|
|
39
|
+
|
|
40
|
+
async def disconnect(self, provider: str, *, level: str | None = "user") -> Any:
|
|
41
|
+
"""Disconnect Integration"""
|
|
42
|
+
return await self._request("DELETE", f"/integrations/{provider}", params={"level": level})
|
|
43
|
+
|
|
44
|
+
async def get_status(self, provider: str) -> IntegrationDetailResponse:
|
|
45
|
+
"""Get Integration Status"""
|
|
46
|
+
return await self._request("GET", f"/integrations/{provider}", response_model=IntegrationDetailResponse)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
4
|
+
from islo.models import (
|
|
5
|
+
ModelPricingResponse,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Models(SyncAPIResource):
|
|
10
|
+
def get_pricing(self) -> ModelPricingResponse:
|
|
11
|
+
"""Get model pricing"""
|
|
12
|
+
return self._request("GET", "/models/pricing", response_model=ModelPricingResponse)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AsyncModels(AsyncAPIResource):
|
|
16
|
+
async def get_pricing(self) -> ModelPricingResponse:
|
|
17
|
+
"""Get model pricing"""
|
|
18
|
+
return await self._request("GET", "/models/pricing", response_model=ModelPricingResponse)
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
6
|
+
from islo.models import (
|
|
7
|
+
AgentSessionEventResponse,
|
|
8
|
+
AgentSessionResponse,
|
|
9
|
+
ExecLogsResponse,
|
|
10
|
+
ExecRequest,
|
|
11
|
+
ExecResponse,
|
|
12
|
+
ExecSessionResponse,
|
|
13
|
+
PaginatedSandboxResponse,
|
|
14
|
+
SandboxCreate,
|
|
15
|
+
SandboxResponse,
|
|
16
|
+
SyncExecRequest,
|
|
17
|
+
SyncExecResponse,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Sandboxes(SyncAPIResource):
|
|
22
|
+
def list(
|
|
23
|
+
self,
|
|
24
|
+
*,
|
|
25
|
+
search: str | None = None,
|
|
26
|
+
status: str | None = None,
|
|
27
|
+
date_from: str | None = None,
|
|
28
|
+
date_to: str | None = None,
|
|
29
|
+
created_by: str | None = None,
|
|
30
|
+
limit: int | None = 50,
|
|
31
|
+
offset: int | None = 0,
|
|
32
|
+
) -> PaginatedSandboxResponse:
|
|
33
|
+
"""List sandboxes"""
|
|
34
|
+
return self._request(
|
|
35
|
+
"GET",
|
|
36
|
+
"/sandboxes/",
|
|
37
|
+
params={
|
|
38
|
+
"search": search,
|
|
39
|
+
"status": status,
|
|
40
|
+
"date_from": date_from,
|
|
41
|
+
"date_to": date_to,
|
|
42
|
+
"created_by": created_by,
|
|
43
|
+
"limit": limit,
|
|
44
|
+
"offset": offset,
|
|
45
|
+
},
|
|
46
|
+
response_model=PaginatedSandboxResponse,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def create(self, *, body: SandboxCreate) -> SandboxResponse:
|
|
50
|
+
"""Create sandbox"""
|
|
51
|
+
return self._request("POST", "/sandboxes/", json_body=body, response_model=SandboxResponse)
|
|
52
|
+
|
|
53
|
+
def list_agent_sessions(
|
|
54
|
+
self, sandbox_id: str, *, since: str | None = None, include_subagents: bool | None = False
|
|
55
|
+
) -> list[AgentSessionResponse]:
|
|
56
|
+
"""List agent sessions"""
|
|
57
|
+
return self._request(
|
|
58
|
+
"GET",
|
|
59
|
+
f"/sandboxes/{sandbox_id}/agent-sessions",
|
|
60
|
+
params={"since": since, "include_subagents": include_subagents},
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def get_agent_session_events(
|
|
64
|
+
self,
|
|
65
|
+
sandbox_id: str,
|
|
66
|
+
session_name: str,
|
|
67
|
+
*,
|
|
68
|
+
session_path: str | None = None,
|
|
69
|
+
include_descendants: bool | None = True,
|
|
70
|
+
limit: int | None = 500,
|
|
71
|
+
offset: int | None = 0,
|
|
72
|
+
since: str | None = None,
|
|
73
|
+
) -> list[AgentSessionEventResponse]:
|
|
74
|
+
"""Get agent session events"""
|
|
75
|
+
return self._request(
|
|
76
|
+
"GET",
|
|
77
|
+
f"/sandboxes/{sandbox_id}/agent-sessions/{session_name}/events",
|
|
78
|
+
params={
|
|
79
|
+
"session_path": session_path,
|
|
80
|
+
"include_descendants": include_descendants,
|
|
81
|
+
"limit": limit,
|
|
82
|
+
"offset": offset,
|
|
83
|
+
"since": since,
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def list_exec_sessions(self, sandbox_id: str, *, since: str | None = None) -> list[ExecSessionResponse]:
|
|
88
|
+
"""List exec sessions"""
|
|
89
|
+
return self._request("GET", f"/sandboxes/{sandbox_id}/exec-sessions", params={"since": since})
|
|
90
|
+
|
|
91
|
+
def get_exec_session_asciinema(self, sandbox_id: str, exec_id: str, *, limit: int | None = 2000) -> Any:
|
|
92
|
+
"""Get exec session as asciinema cast"""
|
|
93
|
+
return self._request(
|
|
94
|
+
"GET", f"/sandboxes/{sandbox_id}/exec-sessions/{exec_id}/asciinema", params={"limit": limit}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def get_exec_session_logs(
|
|
98
|
+
self, sandbox_id: str, exec_id: str, *, limit: int | None = 2000, since: str | None = None
|
|
99
|
+
) -> ExecLogsResponse:
|
|
100
|
+
"""Get exec session logs"""
|
|
101
|
+
return self._request(
|
|
102
|
+
"GET",
|
|
103
|
+
f"/sandboxes/{sandbox_id}/exec-sessions/{exec_id}/logs",
|
|
104
|
+
params={"limit": limit, "since": since},
|
|
105
|
+
response_model=ExecLogsResponse,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def delete(self, sandbox_name: str) -> Any:
|
|
109
|
+
"""Remove sandbox"""
|
|
110
|
+
return self._request("DELETE", f"/sandboxes/{sandbox_name}")
|
|
111
|
+
|
|
112
|
+
def get(self, sandbox_name: str) -> SandboxResponse:
|
|
113
|
+
"""Get sandbox"""
|
|
114
|
+
return self._request("GET", f"/sandboxes/{sandbox_name}", response_model=SandboxResponse)
|
|
115
|
+
|
|
116
|
+
def exec(self, sandbox_name: str, *, body: ExecRequest) -> ExecResponse:
|
|
117
|
+
"""Execute command"""
|
|
118
|
+
return self._request("POST", f"/sandboxes/{sandbox_name}/exec", json_body=body, response_model=ExecResponse)
|
|
119
|
+
|
|
120
|
+
def exec_stream(self, sandbox_name: str, *, body: ExecRequest) -> Any:
|
|
121
|
+
"""Execute command with streaming"""
|
|
122
|
+
return self._request("POST", f"/sandboxes/{sandbox_name}/exec/stream", json_body=body)
|
|
123
|
+
|
|
124
|
+
def promote_cache(self, sandbox_name: str) -> Any:
|
|
125
|
+
"""Promote cache"""
|
|
126
|
+
return self._request("POST", f"/sandboxes/{sandbox_name}/promote-cache")
|
|
127
|
+
|
|
128
|
+
def stop(self, sandbox_name: str) -> Any:
|
|
129
|
+
"""Stop sandbox"""
|
|
130
|
+
return self._request("POST", f"/sandboxes/{sandbox_name}/stop")
|
|
131
|
+
|
|
132
|
+
def exec_sync(self, sandbox_name: str, *, body: SyncExecRequest) -> SyncExecResponse:
|
|
133
|
+
"""Execute a command synchronously and return stdout/stderr/exit_code."""
|
|
134
|
+
return self._request(
|
|
135
|
+
"POST", f"/sandboxes/{sandbox_name}/exec/sync", json_body=body, response_model=SyncExecResponse
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class AsyncSandboxes(AsyncAPIResource):
|
|
140
|
+
async def list(
|
|
141
|
+
self,
|
|
142
|
+
*,
|
|
143
|
+
search: str | None = None,
|
|
144
|
+
status: str | None = None,
|
|
145
|
+
date_from: str | None = None,
|
|
146
|
+
date_to: str | None = None,
|
|
147
|
+
created_by: str | None = None,
|
|
148
|
+
limit: int | None = 50,
|
|
149
|
+
offset: int | None = 0,
|
|
150
|
+
) -> PaginatedSandboxResponse:
|
|
151
|
+
"""List sandboxes"""
|
|
152
|
+
return await self._request(
|
|
153
|
+
"GET",
|
|
154
|
+
"/sandboxes/",
|
|
155
|
+
params={
|
|
156
|
+
"search": search,
|
|
157
|
+
"status": status,
|
|
158
|
+
"date_from": date_from,
|
|
159
|
+
"date_to": date_to,
|
|
160
|
+
"created_by": created_by,
|
|
161
|
+
"limit": limit,
|
|
162
|
+
"offset": offset,
|
|
163
|
+
},
|
|
164
|
+
response_model=PaginatedSandboxResponse,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
async def create(self, *, body: SandboxCreate) -> SandboxResponse:
|
|
168
|
+
"""Create sandbox"""
|
|
169
|
+
return await self._request("POST", "/sandboxes/", json_body=body, response_model=SandboxResponse)
|
|
170
|
+
|
|
171
|
+
async def list_agent_sessions(
|
|
172
|
+
self, sandbox_id: str, *, since: str | None = None, include_subagents: bool | None = False
|
|
173
|
+
) -> list[AgentSessionResponse]:
|
|
174
|
+
"""List agent sessions"""
|
|
175
|
+
return await self._request(
|
|
176
|
+
"GET",
|
|
177
|
+
f"/sandboxes/{sandbox_id}/agent-sessions",
|
|
178
|
+
params={"since": since, "include_subagents": include_subagents},
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
async def get_agent_session_events(
|
|
182
|
+
self,
|
|
183
|
+
sandbox_id: str,
|
|
184
|
+
session_name: str,
|
|
185
|
+
*,
|
|
186
|
+
session_path: str | None = None,
|
|
187
|
+
include_descendants: bool | None = True,
|
|
188
|
+
limit: int | None = 500,
|
|
189
|
+
offset: int | None = 0,
|
|
190
|
+
since: str | None = None,
|
|
191
|
+
) -> list[AgentSessionEventResponse]:
|
|
192
|
+
"""Get agent session events"""
|
|
193
|
+
return await self._request(
|
|
194
|
+
"GET",
|
|
195
|
+
f"/sandboxes/{sandbox_id}/agent-sessions/{session_name}/events",
|
|
196
|
+
params={
|
|
197
|
+
"session_path": session_path,
|
|
198
|
+
"include_descendants": include_descendants,
|
|
199
|
+
"limit": limit,
|
|
200
|
+
"offset": offset,
|
|
201
|
+
"since": since,
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
async def list_exec_sessions(self, sandbox_id: str, *, since: str | None = None) -> list[ExecSessionResponse]:
|
|
206
|
+
"""List exec sessions"""
|
|
207
|
+
return await self._request("GET", f"/sandboxes/{sandbox_id}/exec-sessions", params={"since": since})
|
|
208
|
+
|
|
209
|
+
async def get_exec_session_asciinema(self, sandbox_id: str, exec_id: str, *, limit: int | None = 2000) -> Any:
|
|
210
|
+
"""Get exec session as asciinema cast"""
|
|
211
|
+
return await self._request(
|
|
212
|
+
"GET", f"/sandboxes/{sandbox_id}/exec-sessions/{exec_id}/asciinema", params={"limit": limit}
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
async def get_exec_session_logs(
|
|
216
|
+
self, sandbox_id: str, exec_id: str, *, limit: int | None = 2000, since: str | None = None
|
|
217
|
+
) -> ExecLogsResponse:
|
|
218
|
+
"""Get exec session logs"""
|
|
219
|
+
return await self._request(
|
|
220
|
+
"GET",
|
|
221
|
+
f"/sandboxes/{sandbox_id}/exec-sessions/{exec_id}/logs",
|
|
222
|
+
params={"limit": limit, "since": since},
|
|
223
|
+
response_model=ExecLogsResponse,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
async def delete(self, sandbox_name: str) -> Any:
|
|
227
|
+
"""Remove sandbox"""
|
|
228
|
+
return await self._request("DELETE", f"/sandboxes/{sandbox_name}")
|
|
229
|
+
|
|
230
|
+
async def get(self, sandbox_name: str) -> SandboxResponse:
|
|
231
|
+
"""Get sandbox"""
|
|
232
|
+
return await self._request("GET", f"/sandboxes/{sandbox_name}", response_model=SandboxResponse)
|
|
233
|
+
|
|
234
|
+
async def exec(self, sandbox_name: str, *, body: ExecRequest) -> ExecResponse:
|
|
235
|
+
"""Execute command"""
|
|
236
|
+
return await self._request(
|
|
237
|
+
"POST", f"/sandboxes/{sandbox_name}/exec", json_body=body, response_model=ExecResponse
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
async def exec_stream(self, sandbox_name: str, *, body: ExecRequest) -> Any:
|
|
241
|
+
"""Execute command with streaming"""
|
|
242
|
+
return await self._request("POST", f"/sandboxes/{sandbox_name}/exec/stream", json_body=body)
|
|
243
|
+
|
|
244
|
+
async def promote_cache(self, sandbox_name: str) -> Any:
|
|
245
|
+
"""Promote cache"""
|
|
246
|
+
return await self._request("POST", f"/sandboxes/{sandbox_name}/promote-cache")
|
|
247
|
+
|
|
248
|
+
async def stop(self, sandbox_name: str) -> Any:
|
|
249
|
+
"""Stop sandbox"""
|
|
250
|
+
return await self._request("POST", f"/sandboxes/{sandbox_name}/stop")
|
|
251
|
+
|
|
252
|
+
async def exec_sync(self, sandbox_name: str, *, body: SyncExecRequest) -> SyncExecResponse:
|
|
253
|
+
"""Execute a command synchronously and return stdout/stderr/exit_code."""
|
|
254
|
+
return await self._request(
|
|
255
|
+
"POST", f"/sandboxes/{sandbox_name}/exec/sync", json_body=body, response_model=SyncExecResponse
|
|
256
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
6
|
+
from islo.models import (
|
|
7
|
+
CreateShareRequest,
|
|
8
|
+
ShareResponse,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Shares(SyncAPIResource):
|
|
13
|
+
def list(self, sandbox_name: str) -> list[ShareResponse]:
|
|
14
|
+
"""List shares"""
|
|
15
|
+
return self._request("GET", f"/sandboxes/{sandbox_name}/shares")
|
|
16
|
+
|
|
17
|
+
def create(self, sandbox_name: str, *, body: CreateShareRequest) -> ShareResponse:
|
|
18
|
+
"""Create share"""
|
|
19
|
+
return self._request("POST", f"/sandboxes/{sandbox_name}/shares", json_body=body, response_model=ShareResponse)
|
|
20
|
+
|
|
21
|
+
def revoke(self, sandbox_name: str, share_id: str) -> Any:
|
|
22
|
+
"""Revoke share"""
|
|
23
|
+
return self._request("DELETE", f"/sandboxes/{sandbox_name}/shares/{share_id}")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AsyncShares(AsyncAPIResource):
|
|
27
|
+
async def list(self, sandbox_name: str) -> list[ShareResponse]:
|
|
28
|
+
"""List shares"""
|
|
29
|
+
return await self._request("GET", f"/sandboxes/{sandbox_name}/shares")
|
|
30
|
+
|
|
31
|
+
async def create(self, sandbox_name: str, *, body: CreateShareRequest) -> ShareResponse:
|
|
32
|
+
"""Create share"""
|
|
33
|
+
return await self._request(
|
|
34
|
+
"POST", f"/sandboxes/{sandbox_name}/shares", json_body=body, response_model=ShareResponse
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
async def revoke(self, sandbox_name: str, share_id: str) -> Any:
|
|
38
|
+
"""Revoke share"""
|
|
39
|
+
return await self._request("DELETE", f"/sandboxes/{sandbox_name}/shares/{share_id}")
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
6
|
+
from islo.models import (
|
|
7
|
+
CreateTenant,
|
|
8
|
+
PublicSubscription,
|
|
9
|
+
PublicTenant,
|
|
10
|
+
TenantSettingsResponse,
|
|
11
|
+
TenantSettingsUpdate,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Tenants(SyncAPIResource):
|
|
16
|
+
def list(self) -> list[PublicTenant]:
|
|
17
|
+
"""Get All Tenants"""
|
|
18
|
+
return self._request("GET", "/tenants/")
|
|
19
|
+
|
|
20
|
+
def create(self, *, body: CreateTenant) -> Any:
|
|
21
|
+
"""Create Tenant"""
|
|
22
|
+
return self._request("POST", "/tenants/", json_body=body)
|
|
23
|
+
|
|
24
|
+
def get_settings(self) -> TenantSettingsResponse:
|
|
25
|
+
"""Get Settings"""
|
|
26
|
+
return self._request("GET", "/tenants/settings", response_model=TenantSettingsResponse)
|
|
27
|
+
|
|
28
|
+
def update_settings(self, *, body: TenantSettingsUpdate) -> TenantSettingsResponse:
|
|
29
|
+
"""Update Settings"""
|
|
30
|
+
return self._request("PATCH", "/tenants/settings", json_body=body, response_model=TenantSettingsResponse)
|
|
31
|
+
|
|
32
|
+
def get_subscription(self) -> PublicSubscription:
|
|
33
|
+
"""Get Subscription"""
|
|
34
|
+
return self._request("GET", "/tenants/subscription", response_model=PublicSubscription)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AsyncTenants(AsyncAPIResource):
|
|
38
|
+
async def list(self) -> list[PublicTenant]:
|
|
39
|
+
"""Get All Tenants"""
|
|
40
|
+
return await self._request("GET", "/tenants/")
|
|
41
|
+
|
|
42
|
+
async def create(self, *, body: CreateTenant) -> Any:
|
|
43
|
+
"""Create Tenant"""
|
|
44
|
+
return await self._request("POST", "/tenants/", json_body=body)
|
|
45
|
+
|
|
46
|
+
async def get_settings(self) -> TenantSettingsResponse:
|
|
47
|
+
"""Get Settings"""
|
|
48
|
+
return await self._request("GET", "/tenants/settings", response_model=TenantSettingsResponse)
|
|
49
|
+
|
|
50
|
+
async def update_settings(self, *, body: TenantSettingsUpdate) -> TenantSettingsResponse:
|
|
51
|
+
"""Update Settings"""
|
|
52
|
+
return await self._request("PATCH", "/tenants/settings", json_body=body, response_model=TenantSettingsResponse)
|
|
53
|
+
|
|
54
|
+
async def get_subscription(self) -> PublicSubscription:
|
|
55
|
+
"""Get Subscription"""
|
|
56
|
+
return await self._request("GET", "/tenants/subscription", response_model=PublicSubscription)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from islo._base import AsyncAPIResource, SyncAPIResource
|
|
4
|
+
from islo.models import (
|
|
5
|
+
SandboxUsageDetail,
|
|
6
|
+
UsageSummary,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Usage(SyncAPIResource):
|
|
11
|
+
def sandbox_usage(self, *, start: str | None = None, end: str | None = None) -> list[SandboxUsageDetail]:
|
|
12
|
+
"""Get detailed usage per sandbox for the authenticated tenant"""
|
|
13
|
+
return self._request("GET", "/usage/me/sandboxes", params={"start": start, "end": end})
|
|
14
|
+
|
|
15
|
+
def summary(self, *, start: str | None = None, end: str | None = None) -> UsageSummary:
|
|
16
|
+
"""Get usage summary for the authenticated tenant"""
|
|
17
|
+
return self._request(
|
|
18
|
+
"GET", "/usage/me/summary", params={"start": start, "end": end}, response_model=UsageSummary
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AsyncUsage(AsyncAPIResource):
|
|
23
|
+
async def sandbox_usage(self, *, start: str | None = None, end: str | None = None) -> list[SandboxUsageDetail]:
|
|
24
|
+
"""Get detailed usage per sandbox for the authenticated tenant"""
|
|
25
|
+
return await self._request("GET", "/usage/me/sandboxes", params={"start": start, "end": end})
|
|
26
|
+
|
|
27
|
+
async def summary(self, *, start: str | None = None, end: str | None = None) -> UsageSummary:
|
|
28
|
+
"""Get usage summary for the authenticated tenant"""
|
|
29
|
+
return await self._request(
|
|
30
|
+
"GET", "/usage/me/summary", params={"start": start, "end": end}, response_model=UsageSummary
|
|
31
|
+
)
|