Skip to content

Commit 653ea81

Browse files
authored
release: graphn 0.1.6 (LoRA support + custom-model update endpoint) (#16)
Two spec-sync PRs (#12 on 2026-05-14, #15 on 2026-05-16) landed regenerated _generated/ on main but neither bumped pyproject, so the new control-plane surface has been sitting in the source tree unreleased on PyPI for a week. This PR closes the gap: bumps to 0.1.6, ships matching ergonomic wrappers + typed fields on the hand-curated resource layer, and adds tests so the new surface is covered, not just compiled. New high-level surface on client.custom_models (sync + async): - update(model_id, *, name=..., min_replicas=..., max_replicas=..., cooldown_seconds=..., extra=...) issues PATCH /v1/{ws}/custom-models/{id}. In-place mutation of the live deployment - no rolling restart, no downtime. Empty PATCH is refused client-side with ValidationError(code="empty_update") one round-trip earlier than the server's 422; an `extra` mapping lets callers PATCH future fields without an SDK release. - supported_architectures() returns a typed SupportedArchitectures catalog from GET /v1/{ws}/custom-models/supported-architectures. Each ArchitectureInfo carries the capability tags (tool_calling, vision, image_input, video_input, streaming, json_mode) the architecture exposes. Intended for driving UI architecture/ capability filters before calling validate(). - create(..., base_model_id=...) wires up the LoRA-import hint. Required on weight_source=s3_* to classify the bundle as an adapter at create-time; optional on weight_source=huggingface where it overrides adapter_config.json::base_model_name_or_path from the upstream repo (useful when the recorded base id isn't a valid HF id, e.g. a local filesystem path used during training). - validate(..., model_size_gb=...) lets callers skip the HF head-bytes probe by supplying a weight-size hint, useful for very large models (405B-class) where the probe stalls validate. Typed LoRA fields on the existing Pydantic types: - CustomModel: artifact_type ("base"|"lora"|None), base_model_id, lora_adapter_name, lora_rank. artifact_type is None on responses from control planes that predate the LoRA work - treat that as "base" for compatibility. - ValidateModelResponse: artifact_type (defaults to "base" on fresh responses, None on legacy), detected_base_model_id, lora_rank. When artifact_type == "lora", the architectures / num_params / estimated_memory_gb / max_context_length fields describe the base model resolved from adapter_config.json, not the adapter itself. New public exports: ArchitectureInfo, SupportedArchitectures, ArtifactType from graphn (and graphn.custom_models). CustomModelCreate.huggingface_model_id is now required on the generated attrs dataclass (was str | Unset). The server has returned 422 for omitted huggingface_model_id on every weight source since 0.1.3 (voltagepark/takao#1997) and the hand-curated client.custom_models.create resource raises ValidationError client-side for S3 imports, so this is the generated type catching up - callers using the keyword-only ergonomic API are unaffected. Tests: 57 pass (43 existing + 14 new) covering both transports. ruff check clean. mypy is clean on every file this PR touches (pre-existing no-any-return errors in _transport.py and tts.py are on main and not regressions). The auto-tag job's CHANGELOG check matches "## [0.1.6] - 2026-05-21" so PyPI publish fires automatically on merge.
1 parent c42e87e commit 653ea81

7 files changed

Lines changed: 601 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,93 @@ No `git tag`, no `git push --tags`, no Actions clicks.
2121

2222
## [Unreleased]
2323

24+
## [0.1.6] — 2026-05-21
25+
26+
Spec-sync release plus a matching round of ergonomic wrappers. Picks
27+
up two new custom-model control-plane endpoints, exposes them
28+
through `client.custom_models`, and adds typed LoRA-adapter fields
29+
to the public `CustomModel` and `ValidateModelResponse` Pydantic
30+
models. The low-level generated client (`graphn._generated`) and
31+
the hand-curated resource layer (`graphn.custom_models`) are both
32+
fully in sync with the upstream OpenAPI spec.
33+
34+
### Added
35+
36+
- `client.custom_models.update(model_id, *, name=..., min_replicas=...,
37+
max_replicas=..., cooldown_seconds=..., extra=...)` (sync and async).
38+
Issues `PATCH /v1/{workspaceId}/custom-models/{modelId}` against the
39+
control plane and returns the refreshed :class:`CustomModel`.
40+
Mutates a vetted set of post-create fields in place against the
41+
live deployment — no rolling restart, no downtime. Immutable fields
42+
(`huggingface_model_id`, `weight_source`, GPU topology, …) are not
43+
exposed; change them by deleting and re-creating the model. The SDK
44+
refuses an empty PATCH client-side (raises
45+
`graphn.ValidationError` with code `empty_update`), one round-trip
46+
earlier than the server's `422`.
47+
- `client.custom_models.supported_architectures()` (sync and async).
48+
Returns a typed :class:`SupportedArchitectures` catalog of model
49+
architectures the platform's serving runtimes can deploy, each
50+
annotated with the capability tags (`tool_calling`, `vision`,
51+
`image_input`, `video_input`, `streaming`, `json_mode`) it exposes.
52+
Intended for driving architecture/capability filters in client UIs
53+
before calling :meth:`client.custom_models.validate`. The list is
54+
updated alongside platform runtime upgrades; clients should not
55+
cache it across build cycles.
56+
- LoRA-adapter visibility on the existing types. `CustomModel` gains
57+
`artifact_type` (`Literal["base", "lora"] | None`), `base_model_id`,
58+
`lora_adapter_name`, and `lora_rank` typed fields; older control
59+
planes that predate the LoRA work leave `artifact_type` unset and
60+
should be treated as `"base"` for compatibility. `ValidateModelResponse`
61+
gains `artifact_type`, `detected_base_model_id`, and `lora_rank` so
62+
callers can detect that a HuggingFace repo contains a LoRA adapter
63+
(via `adapter_config.json`) before deploying. When
64+
`artifact_type == "lora"` on the validate response, the
65+
`architectures` / `num_params` / `estimated_memory_gb` /
66+
`max_context_length` fields describe the **base** model resolved
67+
from `adapter_config.json`, not the adapter itself.
68+
- `client.custom_models.create(..., base_model_id=...)` (sync and async).
69+
Required on `weight_source=s3_*` LoRA imports — it's the only way to
70+
classify the bundle as an adapter at create time; omitting it routes
71+
the import through the base path, and a LoRA bundle that wasn't
72+
declared will deploy to `failed` with an actionable error. Optional
73+
on `weight_source=huggingface`, where it **overrides**
74+
`adapter_config.json::base_model_name_or_path` from the upstream
75+
adapter repo — useful when the recorded base id isn't a valid
76+
HuggingFace id (e.g. a local filesystem path used during training).
77+
The base id must be one of the platform's allowlisted bases (see
78+
`client.custom_models.supported_architectures()`).
79+
- `client.custom_models.validate(..., model_size_gb=...)` (sync and
80+
async). Optional caller-supplied estimate (in GiB) of the on-disk
81+
weights size. When provided, the platform sizes the model-weights
82+
PVC from this hint instead of waiting for a HuggingFace head-bytes
83+
probe; useful for very large models (e.g. 405B) where the probe
84+
would otherwise stall the validate response.
85+
- New public exports from `graphn`: `ArchitectureInfo`,
86+
`SupportedArchitectures`, `ArtifactType`.
87+
88+
### Changed
89+
90+
- `CustomModelCreate.huggingface_model_id` is now a **required**
91+
field on the generated `attrs` dataclass (previously
92+
`str | Unset`). This mirrors the server-side behavior already
93+
shipped in v0.1.3 (the control plane has returned `422` for omitted
94+
`huggingface_model_id` on every weight source since
95+
voltagepark/takao#1997) and the client-side `ValidationError` the
96+
high-level `client.custom_models.create` resource has raised since
97+
v0.1.3. The generated type just catches up; callers using the
98+
hand-curated `client.custom_models.create` keyword-only API are
99+
unaffected — the high-level resource still accepts
100+
`huggingface_model_id` as a keyword argument and the existing
101+
client-side guard fires before the request is built.
102+
- `CustomModelCreate.s3_role_arn` docstring now records the
103+
`graphn-byom-*` role-name prefix the platform enforces. No wire or
104+
validation change in the SDK; the constraint has been server-side
105+
since 0.1.3 and the customer-facing CloudFormation template
106+
enforces the same prefix at stack-create time. Doc-only.
107+
- `CustomModel.gpu_memory_utilization` docstring no longer names the
108+
serving engine (`vLLM`). Engine-agnostic wording aligns with the
109+
0.1.3 scrub of customer-facing serving-engine references.
110+
24111
## [0.1.5] — 2026-05-14
25112

26113
Patch release. Widens the upper bound on the `openai` runtime

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "graphn"
7-
version = "0.1.5"
7+
version = "0.1.6"
88
description = "Official Python SDK for the Graphn API: custom-model lifecycle, secrets, and OpenAI-compatible inference."
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/graphn/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@
2222
from graphn._pagination import AsyncPage, SyncPage
2323
from graphn._version import __version__
2424
from graphn.custom_models.types import (
25+
ArchitectureInfo,
26+
ArtifactType,
2527
Capability,
2628
CustomModel,
2729
CustomModelAccess,
2830
CustomModelStatus,
2931
GpuHoursResponse,
3032
Quantization,
33+
SupportedArchitectures,
3134
ValidateModelResponse,
3235
WeightSource,
3336
)
@@ -36,6 +39,8 @@
3639
__all__ = [
3740
"APIConnectionError",
3841
"APIError",
42+
"ArchitectureInfo",
43+
"ArtifactType",
3944
"AsyncClient",
4045
"AsyncPage",
4146
"AuthenticationError",
@@ -53,6 +58,7 @@
5358
"RateLimitError",
5459
"Secret",
5560
"ServerError",
61+
"SupportedArchitectures",
5662
"SyncPage",
5763
"ValidateModelResponse",
5864
"ValidationError",
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
"""Custom-model resource module."""
22

33
from graphn.custom_models.types import (
4+
ArchitectureInfo,
5+
ArtifactType,
46
Capability,
57
CustomModel,
68
CustomModelStatus,
9+
SupportedArchitectures,
710
WeightSource,
811
)
912

10-
__all__ = ["Capability", "CustomModel", "CustomModelStatus", "WeightSource"]
13+
__all__ = [
14+
"ArchitectureInfo",
15+
"ArtifactType",
16+
"Capability",
17+
"CustomModel",
18+
"CustomModelStatus",
19+
"SupportedArchitectures",
20+
"WeightSource",
21+
]

0 commit comments

Comments
 (0)