fix: renamed sandbox to capsule

This commit is contained in:
Tasnim Kabir Sadik
2026-04-13 03:16:27 +06:00
parent 976af9a209
commit bf5914c0a8
14 changed files with 1929 additions and 1805 deletions

View File

@ -1,22 +1,7 @@
from wrenn.client import AsyncWrennClient, WrennClient
from wrenn.exceptions import (
WrennAgentError,
WrennAuthenticationError,
WrennConflictError,
WrennError,
WrennForbiddenError,
WrennHostHasSandboxesError,
WrennHostUnavailableError,
WrennInternalError,
WrennNotFoundError,
WrennValidationError,
)
from wrenn.models import FileEntry
from wrenn.pty import AsyncPtySession, PtyEvent, PtyEventType, PtySession
from wrenn.sandbox import (
from wrenn.capsule import (
Capsule,
CodeResult,
ExecResult,
Sandbox,
StreamErrorEvent,
StreamEvent,
StreamExitEvent,
@ -24,6 +9,21 @@ from wrenn.sandbox import (
StreamStderrEvent,
StreamStdoutEvent,
)
from wrenn.client import AsyncWrennClient, WrennClient
from wrenn.exceptions import (
WrennAgentError,
WrennAuthenticationError,
WrennConflictError,
WrennError,
WrennForbiddenError,
WrennHostHasCapsulesError,
WrennHostUnavailableError,
WrennInternalError,
WrennNotFoundError,
WrennValidationError,
)
from wrenn.models import FileEntry
from wrenn.pty import AsyncPtySession, PtyEvent, PtyEventType, PtySession
__version__ = "0.1.0"
@ -31,6 +31,7 @@ __all__ = [
"__version__",
"AsyncPtySession",
"AsyncWrennClient",
"Capsule",
"CodeResult",
"ExecResult",
"FileEntry",
@ -50,9 +51,32 @@ __all__ = [
"WrennConflictError",
"WrennError",
"WrennForbiddenError",
"WrennHostHasCapsulesError",
"WrennHostHasSandboxesError",
"WrennHostUnavailableError",
"WrennInternalError",
"WrennNotFoundError",
"WrennValidationError",
]
def __getattr__(name: str) -> type:
if name == "Sandbox":
import warnings
warnings.warn(
"'Sandbox' is deprecated, use 'Capsule' instead",
DeprecationWarning,
stacklevel=2,
)
return Capsule
if name == "WrennHostHasSandboxesError":
import warnings
warnings.warn(
"'WrennHostHasSandboxesError' is deprecated, use 'WrennHostHasCapsulesError' instead",
DeprecationWarning,
stacklevel=2,
)
return WrennHostHasCapsulesError
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

1171
src/wrenn/capsule.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,12 @@
from __future__ import annotations
import builtins
import warnings
from typing import cast
import httpx
from wrenn.capsule import Capsule
from wrenn.exceptions import handle_response
from wrenn.models import (
APIKeyResponse,
@ -14,9 +16,8 @@ from wrenn.models import (
Template,
)
from wrenn.models import (
Sandbox as SandboxModel,
Capsule as CapsuleModel,
)
from wrenn.sandbox import Sandbox
DEFAULT_BASE_URL = "https://api.wrenn.dev"
@ -112,8 +113,8 @@ class AsyncAPIKeysResource:
handle_response(resp)
class SandboxesResource:
"""Sync sandbox control-plane operations."""
class CapsulesResource:
"""Sync capsule control-plane operations."""
def __init__(
self,
@ -133,7 +134,7 @@ class SandboxesResource:
vcpus: int | None = None,
memory_mb: int | None = None,
timeout_sec: int | None = None,
) -> Sandbox:
) -> Capsule:
payload: dict = {}
if template is not None:
payload["template"] = template
@ -143,27 +144,27 @@ class SandboxesResource:
payload["memory_mb"] = memory_mb
if timeout_sec is not None:
payload["timeout_sec"] = timeout_sec
resp = self._http.post("/v1/sandboxes", json=payload)
model = SandboxModel.model_validate(handle_response(resp))
sb = Sandbox.model_validate(model.model_dump())
sb._bind(self._http, self._base_url, self._api_key, self._token)
return sb
resp = self._http.post("/v1/capsules", json=payload)
model = CapsuleModel.model_validate(handle_response(resp))
cap = Capsule.model_validate(model.model_dump())
cap._bind(self._http, self._base_url, self._api_key, self._token)
return cap
def list(self) -> list[SandboxModel]:
resp = self._http.get("/v1/sandboxes")
return [SandboxModel.model_validate(item) for item in handle_response(resp)]
def list(self) -> list[CapsuleModel]:
resp = self._http.get("/v1/capsules")
return [CapsuleModel.model_validate(item) for item in handle_response(resp)]
def get(self, id: str) -> SandboxModel:
resp = self._http.get(f"/v1/sandboxes/{id}")
return SandboxModel.model_validate(handle_response(resp))
def get(self, id: str) -> CapsuleModel:
resp = self._http.get(f"/v1/capsules/{id}")
return CapsuleModel.model_validate(handle_response(resp))
def destroy(self, id: str) -> None:
resp = self._http.delete(f"/v1/sandboxes/{id}")
resp = self._http.delete(f"/v1/capsules/{id}")
handle_response(resp)
class AsyncSandboxesResource:
"""Async sandbox control-plane operations."""
class AsyncCapsulesResource:
"""Async capsule control-plane operations."""
def __init__(
self,
@ -183,7 +184,7 @@ class AsyncSandboxesResource:
vcpus: int | None = None,
memory_mb: int | None = None,
timeout_sec: int | None = None,
) -> Sandbox:
) -> Capsule:
payload: dict = {}
if template is not None:
payload["template"] = template
@ -193,22 +194,22 @@ class AsyncSandboxesResource:
payload["memory_mb"] = memory_mb
if timeout_sec is not None:
payload["timeout_sec"] = timeout_sec
resp = await self._http.post("/v1/sandboxes", json=payload)
model = SandboxModel.model_validate(handle_response(resp))
sb = Sandbox.model_validate(model.model_dump())
sb._bind(self._http, self._base_url, self._api_key, self._token)
return sb
resp = await self._http.post("/v1/capsules", json=payload)
model = CapsuleModel.model_validate(handle_response(resp))
cap = Capsule.model_validate(model.model_dump())
cap._bind(self._http, self._base_url, self._api_key, self._token)
return cap
async def list(self) -> list[SandboxModel]:
resp = await self._http.get("/v1/sandboxes")
return [SandboxModel.model_validate(item) for item in handle_response(resp)]
async def list(self) -> list[CapsuleModel]:
resp = await self._http.get("/v1/capsules")
return [CapsuleModel.model_validate(item) for item in handle_response(resp)]
async def get(self, id: str) -> SandboxModel:
resp = await self._http.get(f"/v1/sandboxes/{id}")
return SandboxModel.model_validate(handle_response(resp))
async def get(self, id: str) -> CapsuleModel:
resp = await self._http.get(f"/v1/capsules/{id}")
return CapsuleModel.model_validate(handle_response(resp))
async def destroy(self, id: str) -> None:
resp = await self._http.delete(f"/v1/sandboxes/{id}")
resp = await self._http.delete(f"/v1/capsules/{id}")
handle_response(resp)
@ -220,11 +221,11 @@ class SnapshotsResource:
def create(
self,
sandbox_id: str,
capsule_id: str,
name: str | None = None,
overwrite: bool = False,
) -> Template:
payload: dict = {"sandbox_id": sandbox_id}
payload: dict = {"sandbox_id": capsule_id}
if name is not None:
payload["name"] = name
params: dict = {}
@ -253,11 +254,11 @@ class AsyncSnapshotsResource:
async def create(
self,
sandbox_id: str,
capsule_id: str,
name: str | None = None,
overwrite: bool = False,
) -> Template:
payload: dict = {"sandbox_id": sandbox_id}
payload: dict = {"sandbox_id": capsule_id}
if name is not None:
payload["name"] = name
params: dict = {}
@ -410,10 +411,19 @@ class WrennClient:
self.auth = AuthResource(self._http)
self.api_keys = APIKeysResource(self._http)
self.sandboxes = SandboxesResource(self._http, base_url, api_key, token)
self.capsules = CapsulesResource(self._http, base_url, api_key, token)
self.snapshots = SnapshotsResource(self._http)
self.hosts = HostsResource(self._http)
@property
def sandboxes(self) -> CapsulesResource:
warnings.warn(
"'client.sandboxes' is deprecated, use 'client.capsules' instead",
DeprecationWarning,
stacklevel=2,
)
return self.capsules
def close(self) -> None:
"""Close the underlying HTTP connection pool."""
self._http.close()
@ -458,10 +468,19 @@ class AsyncWrennClient:
self.auth = AsyncAuthResource(self._http)
self.api_keys = AsyncAPIKeysResource(self._http)
self.sandboxes = AsyncSandboxesResource(self._http, base_url, api_key, token)
self.capsules = AsyncCapsulesResource(self._http, base_url, api_key, token)
self.snapshots = AsyncSnapshotsResource(self._http)
self.hosts = AsyncHostsResource(self._http)
@property
def sandboxes(self) -> AsyncCapsulesResource:
warnings.warn(
"'client.sandboxes' is deprecated, use 'client.capsules' instead",
DeprecationWarning,
stacklevel=2,
)
return self.capsules
async def aclose(self) -> None:
"""Close the underlying async HTTP connection pool."""
await self._http.aclose()

View File

@ -1,5 +1,7 @@
from __future__ import annotations
import warnings
import httpx
@ -33,15 +35,24 @@ class WrennConflictError(WrennError):
"""409 — State conflict (e.g. invalid_state)."""
class WrennHostHasSandboxesError(WrennConflictError):
"""409 — Host still has running sandboxes."""
class WrennHostHasCapsulesError(WrennConflictError):
"""409 — Host still has running capsules."""
def __init__(
self, code: str, message: str, status_code: int, sandbox_ids: list[str]
self, code: str, message: str, status_code: int, capsule_ids: list[str]
) -> None:
self.sandbox_ids = sandbox_ids
self.capsule_ids = capsule_ids
super().__init__(code, message, status_code)
@property
def sandbox_ids(self) -> list[str]:
warnings.warn(
"'sandbox_ids' is deprecated, use 'capsule_ids' instead",
DeprecationWarning,
stacklevel=2,
)
return self.capsule_ids
class WrennHostUnavailableError(WrennError):
"""503 — No suitable host available."""
@ -62,7 +73,8 @@ _ERROR_MAP: dict[str, type[WrennError]] = {
"not_found": WrennNotFoundError,
"invalid_state": WrennConflictError,
"conflict": WrennConflictError,
"host_has_sandboxes": WrennHostHasSandboxesError,
"host_has_sandboxes": WrennHostHasCapsulesError,
"host_has_capsules": WrennHostHasCapsulesError,
"host_unavailable": WrennHostUnavailableError,
"agent_error": WrennAgentError,
"internal_error": WrennInternalError,
@ -83,12 +95,12 @@ def handle_response(resp: httpx.Response) -> dict | list:
exc_cls = _ERROR_MAP.get(code, WrennError)
if exc_cls is WrennHostHasSandboxesError:
raise WrennHostHasSandboxesError(
if exc_cls is WrennHostHasCapsulesError:
raise WrennHostHasCapsulesError(
code=code,
message=message,
status_code=resp.status_code,
sandbox_ids=body.get("sandbox_ids", []),
capsule_ids=body.get("sandbox_ids", []),
)
raise exc_cls(
@ -101,3 +113,14 @@ def handle_response(resp: httpx.Response) -> dict | list:
return {}
return resp.json()
def __getattr__(name: str) -> type:
if name == "WrennHostHasSandboxesError":
warnings.warn(
"'WrennHostHasSandboxesError' is deprecated, use 'WrennHostHasCapsulesError' instead",
DeprecationWarning,
stacklevel=2,
)
return WrennHostHasCapsulesError
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

View File

@ -1,10 +1,11 @@
from wrenn.models._generated import (
APIKeyResponse,
AuthResponse,
Capsule,
CreateAPIKeyRequest,
CreateCapsuleRequest,
CreateHostRequest,
CreateHostResponse,
CreateSandboxRequest,
CreateSnapshotRequest,
Encoding,
Error,
@ -22,7 +23,6 @@ from wrenn.models._generated import (
RegisterHostRequest,
RegisterHostResponse,
RemoveRequest,
Sandbox,
SignupRequest,
Status,
Status1,
@ -38,7 +38,7 @@ __all__ = [
"CreateAPIKeyRequest",
"CreateHostRequest",
"CreateHostResponse",
"CreateSandboxRequest",
"CreateCapsuleRequest",
"CreateSnapshotRequest",
"Encoding",
"Error",
@ -56,7 +56,7 @@ __all__ = [
"RegisterHostRequest",
"RegisterHostResponse",
"RemoveRequest",
"Sandbox",
"Capsule",
"SignupRequest",
"Status",
"Status1",

View File

@ -1,6 +1,6 @@
# generated by datamodel-codegen:
# filename: openapi.yaml
# timestamp: 2026-04-11T15:00:55+00:00
# timestamp: 2026-04-12T20:56:29+00:00
from __future__ import annotations
@ -22,7 +22,7 @@ class LoginRequest(BaseModel):
class AuthResponse(BaseModel):
token: Annotated[str | None, Field(description="JWT token (valid for 6 hours)")] = (
token: Annotated[str | None, Field(description='JWT token (valid for 6 hours)')] = (
None
)
user_id: str | None = None
@ -32,7 +32,7 @@ class AuthResponse(BaseModel):
class CreateAPIKeyRequest(BaseModel):
name: str | None = "Unnamed API Key"
name: str | None = 'Unnamed API Key'
class APIKeyResponse(BaseModel):
@ -47,29 +47,29 @@ class APIKeyResponse(BaseModel):
key: Annotated[
str | None,
Field(
description="Full plaintext key. Only returned on creation, never again."
description='Full plaintext key. Only returned on creation, never again.'
),
] = None
class CreateSandboxRequest(BaseModel):
template: str | None = "minimal"
class CreateCapsuleRequest(BaseModel):
template: str | None = 'minimal'
vcpus: int | None = 1
memory_mb: int | None = 512
timeout_sec: Annotated[
int | None,
Field(
description="Auto-pause TTL in seconds. The sandbox is automatically paused after this duration of inactivity (no exec or ping). 0 means no auto-pause.\n"
description='Auto-pause TTL in seconds. The capsule is automatically paused after this duration of inactivity (no exec or ping). 0 means no auto-pause.\n'
),
] = 0
class Range(StrEnum):
field_5m = "5m"
field_1h = "1h"
field_6h = "6h"
field_24h = "24h"
field_30d = "30d"
field_5m = '5m'
field_1h = '1h'
field_6h = '6h'
field_24h = '24h'
field_30d = '30d'
class Current(BaseModel):
@ -100,29 +100,29 @@ class Series(BaseModel):
memory_mb: list[int] | None = None
class SandboxStats(BaseModel):
class CapsuleStats(BaseModel):
range: Range | None = None
current: Current | None = None
peaks: Annotated[
Peaks | None, Field(description="Maximum values over the last 30 days.")
Peaks | None, Field(description='Maximum values over the last 30 days.')
] = None
series: Annotated[
Series | None, Field(description="Parallel arrays for chart rendering.")
Series | None, Field(description='Parallel arrays for chart rendering.')
] = None
class Status(StrEnum):
pending = "pending"
starting = "starting"
running = "running"
paused = "paused"
hibernated = "hibernated"
stopped = "stopped"
missing = "missing"
error = "error"
pending = 'pending'
starting = 'starting'
running = 'running'
paused = 'paused'
hibernated = 'hibernated'
stopped = 'stopped'
missing = 'missing'
error = 'error'
class Sandbox(BaseModel):
class Capsule(BaseModel):
id: str | None = None
status: Status | None = None
template: str | None = None
@ -139,17 +139,17 @@ class Sandbox(BaseModel):
class CreateSnapshotRequest(BaseModel):
sandbox_id: Annotated[
str, Field(description="ID of the running sandbox to snapshot.")
str, Field(description='ID of the running capsule to snapshot.')
]
name: Annotated[
str | None,
Field(description="Name for the snapshot template. Auto-generated if omitted."),
Field(description='Name for the snapshot template. Auto-generated if omitted.'),
] = None
class Type(StrEnum):
base = "base"
snapshot = "snapshot"
base = 'base'
snapshot = 'snapshot'
class Template(BaseModel):
@ -172,8 +172,8 @@ class Encoding(StrEnum):
Output encoding. "base64" when stdout/stderr contain binary data.
"""
utf_8 = "utf-8"
base64 = "base64"
utf_8 = 'utf-8'
base64 = 'base64'
class ExecResponse(BaseModel):
@ -192,23 +192,23 @@ class ExecResponse(BaseModel):
class ReadFileRequest(BaseModel):
path: Annotated[str, Field(description="Absolute file path inside the sandbox")]
path: Annotated[str, Field(description='Absolute file path inside the capsule')]
class ListDirRequest(BaseModel):
path: Annotated[str, Field(description="Directory path inside the sandbox")]
path: Annotated[str, Field(description='Directory path inside the capsule')]
depth: Annotated[
int | None,
Field(
description="Recursion depth (0 = non-recursive, 1 = immediate children)"
description='Recursion depth (0 = non-recursive, 1 = immediate children)'
),
] = 1
class Type1(StrEnum):
file = "file"
directory = "directory"
symlink = "symlink"
file = 'file'
directory = 'directory'
symlink = 'symlink'
class FileEntry(BaseModel):
@ -223,14 +223,14 @@ class FileEntry(BaseModel):
owner: str | None = None
group: str | None = None
modified_at: Annotated[
int | None, Field(description="Unix timestamp (seconds)")
int | None, Field(description='Unix timestamp (seconds)')
] = None
symlink_target: str | None = None
class MakeDirRequest(BaseModel):
path: Annotated[
str, Field(description="Directory path to create inside the sandbox")
str, Field(description='Directory path to create inside the capsule')
]
@ -239,7 +239,7 @@ class MakeDirResponse(BaseModel):
class RemoveRequest(BaseModel):
path: Annotated[str, Field(description="Path to remove inside the sandbox")]
path: Annotated[str, Field(description='Path to remove inside the capsule')]
class Type2(StrEnum):
@ -247,51 +247,51 @@ class Type2(StrEnum):
Host type. Regular hosts are shared; BYOC hosts belong to a team.
"""
regular = "regular"
byoc = "byoc"
regular = 'regular'
byoc = 'byoc'
class CreateHostRequest(BaseModel):
type: Annotated[
Type2,
Field(
description="Host type. Regular hosts are shared; BYOC hosts belong to a team."
description='Host type. Regular hosts are shared; BYOC hosts belong to a team.'
),
]
team_id: Annotated[str | None, Field(description="Required for BYOC hosts.")] = None
team_id: Annotated[str | None, Field(description='Required for BYOC hosts.')] = None
provider: Annotated[
str | None,
Field(description="Cloud provider (e.g. aws, gcp, hetzner, bare-metal)."),
Field(description='Cloud provider (e.g. aws, gcp, hetzner, bare-metal).'),
] = None
availability_zone: Annotated[
str | None, Field(description="Availability zone (e.g. us-east, eu-west).")
str | None, Field(description='Availability zone (e.g. us-east, eu-west).')
] = None
class RegisterHostRequest(BaseModel):
token: Annotated[
str, Field(description="One-time registration token from POST /v1/hosts.")
str, Field(description='One-time registration token from POST /v1/hosts.')
]
arch: Annotated[
str | None, Field(description="CPU architecture (e.g. x86_64, aarch64).")
str | None, Field(description='CPU architecture (e.g. x86_64, aarch64).')
] = None
cpu_cores: int | None = None
memory_mb: int | None = None
disk_gb: int | None = None
address: Annotated[str, Field(description="Host agent address (ip:port).")]
address: Annotated[str, Field(description='Host agent address (ip:port).')]
class Type3(StrEnum):
regular = "regular"
byoc = "byoc"
regular = 'regular'
byoc = 'byoc'
class Status1(StrEnum):
pending = "pending"
online = "online"
offline = "offline"
draining = "draining"
unreachable = "unreachable"
pending = 'pending'
online = 'online'
offline = 'offline'
draining = 'draining'
unreachable = 'unreachable'
class Host(BaseModel):
@ -316,7 +316,7 @@ class RefreshHostTokenRequest(BaseModel):
refresh_token: Annotated[
str,
Field(
description="Refresh token obtained from registration or a previous refresh."
description='Refresh token obtained from registration or a previous refresh.'
),
]
@ -324,12 +324,12 @@ class RefreshHostTokenRequest(BaseModel):
class RefreshHostTokenResponse(BaseModel):
host: Host | None = None
token: Annotated[
str | None, Field(description="New host JWT. Valid for 7 days.")
str | None, Field(description='New host JWT. Valid for 7 days.')
] = None
refresh_token: Annotated[
str | None,
Field(
description="New refresh token. Valid for 60 days; old token is revoked."
description='New refresh token. Valid for 60 days; old token is revoked.'
),
] = None
@ -338,20 +338,20 @@ class HostDeletePreview(BaseModel):
host: Host | None = None
sandbox_ids: Annotated[
list[str] | None,
Field(description="IDs of sandboxes that would be destroyed on force-delete."),
Field(description='IDs of capsulees that would be destroyed on force-delete.'),
] = None
class Error(BaseModel):
code: Annotated[str | None, Field(examples=["host_has_sandboxes"])] = None
code: Annotated[str | None, Field(examples=['host_has_sandboxes'])] = None
message: str | None = None
sandbox_ids: Annotated[
list[str] | None,
Field(description="IDs of active sandboxes blocking deletion."),
Field(description='IDs of active capsulees blocking deletion.'),
] = None
class HostHasSandboxesError(BaseModel):
class HostHasCapsulesError(BaseModel):
error: Error | None = None
@ -368,15 +368,15 @@ class Team(BaseModel):
id: str | None = None
name: str | None = None
slug: Annotated[
str | None, Field(description="Immutable 12-char hex slug (e.g. a1b2c3-d1e2f3)")
str | None, Field(description='Immutable 12-char hex slug (e.g. a1b2c3-d1e2f3)')
] = None
created_at: AwareDatetime | None = None
class Role(StrEnum):
owner = "owner"
admin = "admin"
member = "member"
owner = 'owner'
admin = 'admin'
member = 'member'
class TeamWithRole(Team):
@ -396,13 +396,13 @@ class TeamDetail(BaseModel):
class Range1(StrEnum):
field_5m = "5m"
field_10m = "10m"
field_1h = "1h"
field_2h = "2h"
field_6h = "6h"
field_12h = "12h"
field_24h = "24h"
field_5m = '5m'
field_10m = '10m'
field_1h = '1h'
field_2h = '2h'
field_6h = '6h'
field_12h = '12h'
field_24h = '24h'
class MetricPoint(BaseModel):
@ -410,41 +410,41 @@ class MetricPoint(BaseModel):
cpu_pct: Annotated[
float | None,
Field(
description="CPU utilization percentage (0-100), normalized to vCPU count"
description='CPU utilization percentage (0-100), normalized to vCPU count'
),
] = None
mem_bytes: Annotated[
int | None,
Field(description="Resident memory in bytes (VmRSS of Firecracker process)"),
Field(description='Resident memory in bytes (VmRSS of Firecracker process)'),
] = None
disk_bytes: Annotated[
int | None, Field(description="Allocated disk bytes for the CoW sparse file")
int | None, Field(description='Allocated disk bytes for the CoW sparse file')
] = None
class Provider(StrEnum):
discord = "discord"
slack = "slack"
teams = "teams"
googlechat = "googlechat"
telegram = "telegram"
matrix = "matrix"
webhook = "webhook"
discord = 'discord'
slack = 'slack'
teams = 'teams'
googlechat = 'googlechat'
telegram = 'telegram'
matrix = 'matrix'
webhook = 'webhook'
class Event(StrEnum):
capsule_created = "capsule.created"
capsule_running = "capsule.running"
capsule_paused = "capsule.paused"
capsule_destroyed = "capsule.destroyed"
template_snapshot_created = "template.snapshot.created"
template_snapshot_deleted = "template.snapshot.deleted"
host_up = "host.up"
host_down = "host.down"
capsule_created = 'capsule.created'
capsule_running = 'capsule.running'
capsule_paused = 'capsule.paused'
capsule_destroyed = 'capsule.destroyed'
template_snapshot_created = 'template.snapshot.created'
template_snapshot_deleted = 'template.snapshot.deleted'
host_up = 'host.up'
host_down = 'host.down'
class CreateChannelRequest(BaseModel):
name: Annotated[str, Field(description="Unique channel name within the team.")]
name: Annotated[str, Field(description='Unique channel name within the team.')]
provider: Provider
config: Annotated[
dict[str, str],
@ -460,7 +460,7 @@ class TestChannelRequest(BaseModel):
config: Annotated[
dict[str, str],
Field(
description="Provider-specific configuration fields (same as CreateChannelRequest.config)."
description='Provider-specific configuration fields (same as CreateChannelRequest.config).'
),
]
@ -489,7 +489,7 @@ class ChannelResponse(BaseModel):
updated_at: AwareDatetime | None = None
secret: Annotated[
str | None,
Field(description="Webhook secret. Only returned on creation, never again."),
Field(description='Webhook secret. Only returned on creation, never again.'),
] = None
@ -511,7 +511,7 @@ class CreateHostResponse(BaseModel):
registration_token: Annotated[
str | None,
Field(
description="One-time registration token for the host agent. Expires in 1 hour."
description='One-time registration token for the host agent. Expires in 1 hour.'
),
] = None
@ -520,17 +520,17 @@ class RegisterHostResponse(BaseModel):
host: Host | None = None
token: Annotated[
str | None,
Field(description="Host JWT for X-Host-Token header. Valid for 7 days."),
Field(description='Host JWT for X-Host-Token header. Valid for 7 days.'),
] = None
refresh_token: Annotated[
str | None,
Field(
description="Refresh token for obtaining new JWTs. Valid for 60 days; rotated on each use."
description='Refresh token for obtaining new JWTs. Valid for 60 days; rotated on each use.'
),
] = None
class SandboxMetrics(BaseModel):
class CapsuleMetrics(BaseModel):
sandbox_id: str | None = None
range: Range1 | None = None
points: list[MetricPoint] | None = None

View File

@ -66,9 +66,9 @@ class PtySession:
break
"""
def __init__(self, ws: httpx_ws.WebSocketSession, sandbox_id: str) -> None:
def __init__(self, ws: httpx_ws.WebSocketSession, capsule_id: str) -> None:
self._ws = ws
self._sandbox_id = sandbox_id
self._capsule_id = capsule_id
self._tag: str | None = None
self._pid: int | None = None
self._done = False
@ -192,9 +192,9 @@ class AsyncPtySession:
break
"""
def __init__(self, ws: httpx_ws.AsyncWebSocketSession, sandbox_id: str) -> None:
def __init__(self, ws: httpx_ws.AsyncWebSocketSession, capsule_id: str) -> None:
self._ws = ws
self._sandbox_id = sandbox_id
self._capsule_id = capsule_id
self._tag: str | None = None
self._pid: int | None = None
self._done = False

File diff suppressed because it is too large Load Diff