Version bump
This commit is contained in:
54
README.md
54
README.md
@ -172,6 +172,8 @@ import sys
|
|||||||
# Stream a new command
|
# Stream a new command
|
||||||
for event in capsule.commands.stream("python", args=["-u", "train.py"]):
|
for event in capsule.commands.stream("python", args=["-u", "train.py"]):
|
||||||
match event.type:
|
match event.type:
|
||||||
|
case "start":
|
||||||
|
print(f"PID: {event.pid}")
|
||||||
case "stdout":
|
case "stdout":
|
||||||
print(event.data, end="")
|
print(event.data, end="")
|
||||||
case "stderr":
|
case "stderr":
|
||||||
@ -181,8 +183,11 @@ for event in capsule.commands.stream("python", args=["-u", "train.py"]):
|
|||||||
|
|
||||||
# Connect to a running background process
|
# Connect to a running background process
|
||||||
for event in capsule.commands.connect(handle.pid):
|
for event in capsule.commands.connect(handle.pid):
|
||||||
if event.type == "stdout":
|
match event.type:
|
||||||
print(event.data, end="")
|
case "start":
|
||||||
|
print(f"PID: {event.pid}")
|
||||||
|
case "stdout":
|
||||||
|
print(event.data, end="")
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Process Management
|
#### Process Management
|
||||||
@ -211,6 +216,7 @@ capsule.files.exists("/app/main.py") # True
|
|||||||
|
|
||||||
# List directory
|
# List directory
|
||||||
entries = capsule.files.list("/home/user", depth=1)
|
entries = capsule.files.list("/home/user", depth=1)
|
||||||
|
# FileEntry has: name, type (file/dir), size, modified_at
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
print(entry.name, entry.type, entry.size)
|
print(entry.name, entry.type, entry.size)
|
||||||
|
|
||||||
@ -289,8 +295,27 @@ value = capsule.git.get_config("user.name", cwd="/app") # str | None
|
|||||||
|
|
||||||
capsule.git.remote_add("upstream", "https://github.com/org/repo.git", cwd="/app")
|
capsule.git.remote_add("upstream", "https://github.com/org/repo.git", cwd="/app")
|
||||||
url = capsule.git.remote_get("origin", cwd="/app") # str | None
|
url = capsule.git.remote_get("origin", cwd="/app") # str | None
|
||||||
|
|
||||||
|
# Reset and restore
|
||||||
|
capsule.git.reset(mode="hard", ref="HEAD~1", cwd="/app")
|
||||||
|
capsule.git.restore(["file.txt"], staged=True, cwd="/app")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Persistent Credential Store
|
||||||
|
|
||||||
|
For workflows that need repeated authenticated operations, you can persist credentials via the git credential store:
|
||||||
|
|
||||||
|
```python
|
||||||
|
capsule.git.dangerously_authenticate(
|
||||||
|
username="user",
|
||||||
|
password="ghp_token",
|
||||||
|
host="github.com",
|
||||||
|
protocol="https",
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Warning:** Credentials are written in plaintext inside the capsule and are accessible to any process running there. Prefer per-operation `username`/`password` on `clone`, `push`, and `pull` instead.
|
||||||
|
|
||||||
Git errors raise `GitCommandError` (or `GitAuthError` for authentication failures), both inheriting from `GitError`:
|
Git errors raise `GitCommandError` (or `GitAuthError` for authentication failures), both inheriting from `GitError`:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
@ -308,7 +333,7 @@ except GitAuthError as e:
|
|||||||
```python
|
```python
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
with capsule.pty(cmd="/bin/bash", cols=120, rows=40, cwd="/home/user") as term:
|
with capsule.pty(cmd="/bin/bash", cols=80, rows=24, cwd="/home/user") as term:
|
||||||
term.write(b"ls -la\n")
|
term.write(b"ls -la\n")
|
||||||
for event in term:
|
for event in term:
|
||||||
if event.type == "output":
|
if event.type == "output":
|
||||||
@ -451,9 +476,10 @@ result = capsule.run_code("print('running on custom template')")
|
|||||||
| `logs` | `Logs` | `.stdout: list[str]` and `.stderr: list[str]` chunks |
|
| `logs` | `Logs` | `.stdout: list[str]` and `.stderr: list[str]` chunks |
|
||||||
| `error` | `ExecutionError \| None` | `.name`, `.value`, `.traceback` |
|
| `error` | `ExecutionError \| None` | `.name`, `.value`, `.traceback` |
|
||||||
| `execution_count` | `int \| None` | Jupyter cell execution counter |
|
| `execution_count` | `int \| None` | Jupyter cell execution counter |
|
||||||
|
| `timed_out` | `bool` | ``True`` when execution was cut short by the timeout |
|
||||||
| `text` | `str \| None` | (property) `text/plain` of the main `execute_result` |
|
| `text` | `str \| None` | (property) `text/plain` of the main `execute_result` |
|
||||||
|
|
||||||
Each `Result` has typed MIME fields: `text`, `html`, `markdown`, `svg`, `png`, `jpeg`, `pdf`, `latex`, `json`, `javascript`, plus `extra` for unknown types. The `text` field is Jupyter's `text/plain` bundle verbatim — the Python `repr()` of the cell's last expression. So `run_code("'hi'").text` is `"'hi'"` (with quotes), and `run_code("42").text` is `"42"`. This preserves the distinction between the string `'2'` and the int `2`.
|
Each `Result` has typed MIME fields: `text`, `html`, `markdown`, `svg`, `png`, `jpeg`, `gif`, `pdf`, `latex`, `json`, `javascript`, `plotly`, plus `extra` for unknown types. The `text` field is Jupyter's `text/plain` bundle verbatim — the Python `repr()` of the cell's last expression. So `run_code("'hi'").text` is `"'hi'"` (with quotes), and `run_code("42").text` is `"42"`. This preserves the distinction between the string `'2'` and the int `2`.
|
||||||
|
|
||||||
### Code Runner + Commands/Files
|
### Code Runner + Commands/Files
|
||||||
|
|
||||||
@ -527,15 +553,15 @@ The SDK maps server error codes to typed exceptions:
|
|||||||
```python
|
```python
|
||||||
from wrenn import (
|
from wrenn import (
|
||||||
WrennError,
|
WrennError,
|
||||||
WrennValidationError, # 400
|
WrennValidationError, # 400
|
||||||
WrennAuthenticationError, # 401
|
WrennAuthenticationError, # 401
|
||||||
WrennForbiddenError, # 403
|
WrennForbiddenError, # 403
|
||||||
WrennNotFoundError, # 404
|
WrennNotFoundError, # 404
|
||||||
WrennConflictError, # 409
|
WrennConflictError, # 409
|
||||||
WrennHostHasCapsulesError, # 409 (host has running capsules)
|
WrennHostHasCapsulesError, # 409 (host has running capsules)
|
||||||
WrennAgentError, # 502
|
WrennInternalError, # 500
|
||||||
WrennInternalError, # 500
|
WrennAgentError, # 502
|
||||||
WrennHostUnavailableError, # 503
|
WrennHostUnavailableError, # 503
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -603,7 +629,7 @@ with WrennClient(api_key="wrn_...") as client:
|
|||||||
|
|
||||||
# Snapshots
|
# Snapshots
|
||||||
template = client.snapshots.create(capsule_id="cl-abc", name="my-snap")
|
template = client.snapshots.create(capsule_id="cl-abc", name="my-snap")
|
||||||
templates = client.snapshots.list()
|
templates = client.snapshots.list(type="custom") # optional type filter
|
||||||
client.snapshots.delete("my-snap")
|
client.snapshots.delete("my-snap")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
141
api/openapi.yaml
141
api/openapi.yaml
@ -2716,14 +2716,39 @@ paths:
|
|||||||
tags: [admin]
|
tags: [admin]
|
||||||
security:
|
security:
|
||||||
- sessionAuth: []
|
- sessionAuth: []
|
||||||
|
parameters:
|
||||||
|
- name: page
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
minimum: 1
|
||||||
|
default: 1
|
||||||
|
description: Page number for pagination.
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Teams list
|
description: Paginated teams list
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: array
|
type: object
|
||||||
items: {type: object}
|
properties:
|
||||||
|
teams:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/AdminTeam"
|
||||||
|
total:
|
||||||
|
type: integer
|
||||||
|
page:
|
||||||
|
type: integer
|
||||||
|
per_page:
|
||||||
|
type: integer
|
||||||
|
total_pages:
|
||||||
|
type: integer
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
|
||||||
/v1/admin/teams/{id}/byoc:
|
/v1/admin/teams/{id}/byoc:
|
||||||
put:
|
put:
|
||||||
@ -2743,12 +2768,20 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
required: [byoc]
|
required: [enabled]
|
||||||
properties:
|
properties:
|
||||||
byoc: {type: boolean}
|
enabled:
|
||||||
|
type: boolean
|
||||||
|
description: true to enable BYOC, false to disable.
|
||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: Updated
|
description: Updated
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
|
||||||
/v1/admin/teams/{id}:
|
/v1/admin/teams/{id}:
|
||||||
delete:
|
delete:
|
||||||
@ -2765,6 +2798,38 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
"204":
|
"204":
|
||||||
description: Deleted
|
description: Deleted
|
||||||
|
"400":
|
||||||
|
$ref: "#/components/responses/BadRequest"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
"404":
|
||||||
|
$ref: "#/components/responses/NotFound"
|
||||||
|
|
||||||
|
/v1/admin/hosts:
|
||||||
|
get:
|
||||||
|
summary: List all hosts (admin)
|
||||||
|
operationId: adminListHosts
|
||||||
|
tags: [admin]
|
||||||
|
security:
|
||||||
|
- sessionAuth: []
|
||||||
|
description: |
|
||||||
|
Returns all hosts across all teams with per-host resource consumption.
|
||||||
|
Includes team name for hosts associated with a team.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Hosts list
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Host"
|
||||||
|
"401":
|
||||||
|
$ref: "#/components/responses/Unauthorized"
|
||||||
|
"403":
|
||||||
|
$ref: "#/components/responses/Forbidden"
|
||||||
|
|
||||||
/v1/admin/users:
|
/v1/admin/users:
|
||||||
get:
|
get:
|
||||||
@ -3581,10 +3646,6 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
memory_mb_reserved:
|
memory_mb_reserved:
|
||||||
type: integer
|
type: integer
|
||||||
sampled_at:
|
|
||||||
type: string
|
|
||||||
format: date-time
|
|
||||||
nullable: true
|
|
||||||
peaks:
|
peaks:
|
||||||
type: object
|
type: object
|
||||||
description: Maximum values over the last 30 days.
|
description: Maximum values over the last 30 days.
|
||||||
@ -3633,10 +3694,6 @@ components:
|
|||||||
type: integer
|
type: integer
|
||||||
timeout_sec:
|
timeout_sec:
|
||||||
type: integer
|
type: integer
|
||||||
guest_ip:
|
|
||||||
type: string
|
|
||||||
host_ip:
|
|
||||||
type: string
|
|
||||||
created_at:
|
created_at:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
@ -3661,7 +3718,11 @@ components:
|
|||||||
agent_version, envd_version) when running.
|
agent_version, envd_version) when running.
|
||||||
disk_size_mb:
|
disk_size_mb:
|
||||||
type: integer
|
type: integer
|
||||||
nullable: true
|
description: Maximum disk capacity in MiB.
|
||||||
|
disk_used_mb:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Current disk usage in MiB. Only populated on individual capsule GET; omitted in list responses.
|
||||||
|
|
||||||
CreateSnapshotRequest:
|
CreateSnapshotRequest:
|
||||||
type: object
|
type: object
|
||||||
@ -4013,6 +4074,25 @@ components:
|
|||||||
updated_at:
|
updated_at:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
team_name:
|
||||||
|
type: string
|
||||||
|
nullable: true
|
||||||
|
description: Team name (included when listing hosts as an admin).
|
||||||
|
running_vcpus:
|
||||||
|
type: integer
|
||||||
|
description: Total vCPUs allocated to running capsules on this host.
|
||||||
|
running_memory_mb:
|
||||||
|
type: integer
|
||||||
|
description: Total memory in MB allocated to running capsules on this host.
|
||||||
|
running_disk_mb:
|
||||||
|
type: integer
|
||||||
|
description: Total disk in MB allocated to running capsules on this host.
|
||||||
|
paused_memory_mb:
|
||||||
|
type: integer
|
||||||
|
description: Total memory in MB allocated to paused capsules on this host.
|
||||||
|
paused_disk_mb:
|
||||||
|
type: integer
|
||||||
|
description: Total disk in MB allocated to paused capsules on this host.
|
||||||
|
|
||||||
RefreshHostTokenRequest:
|
RefreshHostTokenRequest:
|
||||||
type: object
|
type: object
|
||||||
@ -4124,6 +4204,39 @@ components:
|
|||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/TeamMember"
|
$ref: "#/components/schemas/TeamMember"
|
||||||
|
|
||||||
|
AdminTeam:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
slug:
|
||||||
|
type: string
|
||||||
|
is_byoc:
|
||||||
|
type: boolean
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
deleted_at:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
nullable: true
|
||||||
|
member_count:
|
||||||
|
type: integer
|
||||||
|
owner_name:
|
||||||
|
type: string
|
||||||
|
owner_email:
|
||||||
|
type: string
|
||||||
|
active_sandbox_count:
|
||||||
|
type: integer
|
||||||
|
channel_count:
|
||||||
|
type: integer
|
||||||
|
running_vcpus:
|
||||||
|
type: integer
|
||||||
|
running_memory_mb:
|
||||||
|
type: integer
|
||||||
|
|
||||||
CapsuleMetrics:
|
CapsuleMetrics:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "wrenn"
|
name = "wrenn"
|
||||||
version = "0.1.5"
|
version = "0.2.0"
|
||||||
description = "Python SDK for Wrenn"
|
description = "Python SDK for Wrenn"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
Reference in New Issue
Block a user