feat: prune SDK to API-key surface, add stats/usage/metrics/events
All checks were successful
ci/woodpecker/push/unit Pipeline was successful

Strip session-only routes (auth, me, teams, hosts, channels, admin,
audit-logs) from api/openapi.yaml via new scripts/prune_openapi.py,
which is wired into `make generate` and `make prune-spec`. Spec drops
from 4787 to 1717 lines; regenerated _generated.py drops from 906 to
415 lines with all obsolete models removed.

Add SDK methods on CapsulesResource / AsyncCapsulesResource for the
apiKey-usable routes that were previously unwrapped:
  - capsules.stats(range=...)         -> CapsuleStats
  - capsules.usage(from_=..., to=...) -> UsageResponse (accepts date)
  - capsules.metrics(id, range=...)   -> CapsuleMetrics

Add EventsResource / AsyncEventsResource exposing
WrennClient.events.stream() over /v1/events/stream (SSE). Parser
handles `:keepalive` comments and multi-line `data:` frames.

Re-export new models (CapsuleStats, CapsuleMetrics, MetricPoint,
UsageResponse, SSEEvent, Resource, Actor) from wrenn.models.

Drop email-validator runtime dep (no EmailStr remains). Bump version
to 0.3.0 (pyproject + __version__). Add pyyaml to dev deps and
types-PyYAML to the pre-commit mypy hook for the prune script.

Normalize docstrings on new methods/classes to Google style with
Example:: blocks where useful. Regenerate docs/reference.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-23 01:28:54 +06:00
parent a2d9aac78b
commit 03cd2227b5
12 changed files with 1915 additions and 3612 deletions

View File

@ -166,6 +166,131 @@ Reset the inactivity timer for a capsule.
- `WrennNotFoundError` - If no capsule with the given ID exists.
<a id="wrenn.client.CapsulesResource.stats"></a>
#### stats
```python
def stats(range: str | None = None) -> CapsuleStats
```
Get aggregate capsule usage stats for the authenticated team.
**Arguments**:
- `range` _str | None_ - Time window. One of ``5m``, ``1h``, ``6h``,
``24h``, ``30d``. Defaults to ``1h`` server-side.
**Returns**:
- `CapsuleStats` - Current running counts plus 30-day peaks and a
chart-ready time series.
Example::
stats = wrenn.capsules.stats(range="24h")
print(stats.current.running_count, stats.peaks.vcpus)
<a id="wrenn.client.CapsulesResource.usage"></a>
#### usage
```python
def usage(from_: str | date | None = None,
to: str | date | None = None) -> UsageResponse
```
Get per-day CPU and RAM usage for the team.
**Arguments**:
- `from_` _str | date | None_ - Start date (``YYYY-MM-DD`` string or
``date``). Defaults to 30 days ago server-side.
- `to` _str | date | None_ - End date. Defaults to today.
**Returns**:
- `UsageResponse` - Daily ``cpu_minutes`` / ``ram_mb_minutes`` points.
Example::
from datetime import date, timedelta
today = date.today()
usage = wrenn.capsules.usage(from_=today - timedelta(days=7), to=today)
for point in usage.points:
print(point.date, point.cpu_minutes, point.ram_mb_minutes)
<a id="wrenn.client.CapsulesResource.metrics"></a>
#### metrics
```python
def metrics(id: str, range: str | None = None) -> CapsuleMetrics
```
Get time-series CPU, memory, and disk metrics for a capsule.
**Arguments**:
- `id` _str_ - Capsule ID.
- `range` _str | None_ - One of ``10m`` (500ms samples),
``2h`` (30s averages), ``24h`` (5-minute averages). Defaults
to ``10m`` server-side.
**Returns**:
- `CapsuleMetrics` - Sampled :class:`MetricPoint` series.
**Raises**:
- `WrennNotFoundError` - If the capsule does not exist or has been
destroyed.
Example::
m = wrenn.capsules.metrics("sb-abc123", range="2h")
for point in m.points:
print(point.timestamp_unix, point.cpu_pct, point.mem_bytes)
<a id="wrenn.client.EventsResource"></a>
## EventsResource Objects
```python
class EventsResource()
```
Sync server-sent event stream of capsule/template/host lifecycle events.
<a id="wrenn.client.EventsResource.stream"></a>
#### stream
```python
def stream() -> Iterator[SSEEvent]
```
Stream lifecycle events for the team in real time.
The connection is held open by the server; iterate the result to
receive :class:`SSEEvent` payloads as they arrive. Close the
iterator (or break out of the loop) to disconnect.
**Yields**:
- `SSEEvent` - One event per server frame.
Example::
with WrennClient() as wrenn:
for ev in wrenn.events.stream():
print(ev.event, ev.resource)
<a id="wrenn.client.AsyncCapsulesResource"></a>
## AsyncCapsulesResource Objects
@ -326,6 +451,129 @@ Reset the inactivity timer for a capsule.
- `WrennNotFoundError` - If no capsule with the given ID exists.
<a id="wrenn.client.AsyncCapsulesResource.stats"></a>
#### stats
```python
async def stats(range: str | None = None) -> CapsuleStats
```
Get aggregate capsule usage stats for the authenticated team.
**Arguments**:
- `range` _str | None_ - Time window. One of ``5m``, ``1h``, ``6h``,
``24h``, ``30d``. Defaults to ``1h`` server-side.
**Returns**:
- `CapsuleStats` - Current running counts plus 30-day peaks and a
chart-ready time series.
Example::
stats = await wrenn.capsules.stats(range="24h")
print(stats.current.running_count, stats.peaks.vcpus)
<a id="wrenn.client.AsyncCapsulesResource.usage"></a>
#### usage
```python
async def usage(from_: str | date | None = None,
to: str | date | None = None) -> UsageResponse
```
Get per-day CPU and RAM usage for the team.
**Arguments**:
- `from_` _str | date | None_ - Start date (``YYYY-MM-DD`` string or
``date``). Defaults to 30 days ago server-side.
- `to` _str | date | None_ - End date. Defaults to today.
**Returns**:
- `UsageResponse` - Daily ``cpu_minutes`` / ``ram_mb_minutes`` points.
Example::
from datetime import date, timedelta
today = date.today()
usage = await wrenn.capsules.usage(
from_=today - timedelta(days=7), to=today
)
for point in usage.points:
print(point.date, point.cpu_minutes, point.ram_mb_minutes)
<a id="wrenn.client.AsyncCapsulesResource.metrics"></a>
#### metrics
```python
async def metrics(id: str, range: str | None = None) -> CapsuleMetrics
```
Get time-series CPU, memory, and disk metrics for a capsule.
**Arguments**:
- `id` _str_ - Capsule ID.
- `range` _str | None_ - One of ``10m`` (500ms samples),
``2h`` (30s averages), ``24h`` (5-minute averages). Defaults
to ``10m`` server-side.
**Returns**:
- `CapsuleMetrics` - Sampled :class:`MetricPoint` series.
**Raises**:
- `WrennNotFoundError` - If the capsule does not exist or has been
destroyed.
Example::
m = await wrenn.capsules.metrics("sb-abc123", range="2h")
for point in m.points:
print(point.timestamp_unix, point.cpu_pct, point.mem_bytes)
<a id="wrenn.client.AsyncEventsResource"></a>
## AsyncEventsResource Objects
```python
class AsyncEventsResource()
```
Async server-sent event stream of capsule/template/host lifecycle events.
<a id="wrenn.client.AsyncEventsResource.stream"></a>
#### stream
```python
async def stream() -> AsyncIterator[SSEEvent]
```
Stream lifecycle events for the team in real time.
**Yields**:
- `SSEEvent` - One event per server frame.
Example::
async with AsyncWrennClient() as wrenn:
async for ev in wrenn.events.stream():
print(ev.event, ev.resource)
<a id="wrenn.client.SnapshotsResource"></a>
## SnapshotsResource Objects
@ -484,7 +732,11 @@ class WrennClient()
Synchronous client for the Wrenn API.
Authenticates with an API key.
Authenticates with an API key. Exposes three resources:
- :attr:`capsules` — capsule lifecycle, stats, usage, metrics
- :attr:`snapshots` — template snapshot management
- :attr:`events` — server-sent lifecycle event stream
**Arguments**:
@ -496,6 +748,15 @@ Authenticates with an API key.
is the default ``app.wrenn.dev`` host, else the ``base_url`` host.
- `timeout` - HTTP timeout. Accepts ``httpx.Timeout``, a float (seconds),
or ``None`` for the default (30s read/write/pool, 10s connect).
Example::
from wrenn import WrennClient
with WrennClient() as wrenn: # reads WRENN_API_KEY
capsule = wrenn.capsules.create(template="minimal-ubuntu")
print(capsule.id, capsule.status)
wrenn.capsules.destroy(capsule.id)
<a id="wrenn.client.WrennClient.http"></a>
@ -528,7 +789,8 @@ class AsyncWrennClient()
Asynchronous client for the Wrenn API.
Authenticates with an API key.
Authenticates with an API key. Mirrors :class:`WrennClient` with
``await``-able methods on every resource.
**Arguments**:
@ -540,6 +802,16 @@ Authenticates with an API key.
is the default ``app.wrenn.dev`` host, else the ``base_url`` host.
- `timeout` - HTTP timeout. Accepts ``httpx.Timeout``, a float (seconds),
or ``None`` for the default (30s read/write/pool, 10s connect).
Example::
from wrenn import AsyncWrennClient
async with AsyncWrennClient() as wrenn:
capsule = await wrenn.capsules.create(template="minimal-ubuntu")
async for event in wrenn.events.stream():
if event.resource and event.resource.id == capsule.id:
break
<a id="wrenn.client.AsyncWrennClient.http"></a>
@ -1936,18 +2208,6 @@ Send SIGKILL to the PTY process.
# wrenn.models.\_generated
<a id="wrenn.models._generated.SessionResponse"></a>
## SessionResponse Objects
```python
class SessionResponse(BaseModel)
```
Returned by login, activate, and switch-team. The actual auth credential
is the wrenn_sid cookie set on the response. The body carries identity
data the SPA needs to bootstrap.
<a id="wrenn.models._generated.Peaks"></a>
## Peaks Objects
@ -1978,16 +2238,6 @@ class Encoding(StrEnum)
Output encoding. "base64" when stdout/stderr contain binary data.
<a id="wrenn.models._generated.Type2"></a>
## Type2 Objects
```python
class Type2(StrEnum)
```
Host type. Regular hosts are shared; BYOC hosts belong to a team.
<a id="wrenn.models._generated.Outcome"></a>
## Outcome Objects