From d7103c1261b1695b7467d9f95ad07105217a6dae Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Tue, 19 May 2026 16:24:32 -0300 Subject: [PATCH 1/4] models: add extra_payload to create_custom / update_custom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the new atlas-app backend field (LayerLens/atlas-app#1932). ``extra_payload`` is an optional JSON object that's deep-merged into every outgoing chat-completions request body — customer values win on conflict with our hardcoded defaults. Lets callers override ``temperature`` (we send 0 for reproducible evals) or add provider-specific fields like ``max_completion_tokens`` that some endpoints require. Updated: - ``models.create_custom`` (sync + async) — new ``extra_payload`` keyword argument. - ``models.update_custom`` (sync + async) — same, plus a docstring note that ``{}`` clears the existing payload. - Reference docs, README example, samples, CHANGELOG. - Example ``api_url`` values now show the full ``/v1/chat/completions`` form to match the backend hint. Existing SDK callers keep working — the field is optional and additive on the backend. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 2 + docs/README.md | 5 +- docs/api-reference/models-benchmarks.md | 58 +++++++++++++++--------- docs/examples/models-and-benchmarks.md | 8 ++-- samples/claude-code/skills/benchmark.md | 2 +- samples/core/custom_model.py | 9 +++- src/layerlens/resources/models/models.py | 43 ++++++++++++++++-- 7 files changed, 94 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e29d1be0..75fe342d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ Things we're actively working on. Want to help? Check the [issues](https://githu ### Added +- `extra_payload` parameter on `models.create_custom` and `models.update_custom` (sync + async). Optional JSON object merged into every outgoing chat-completions request body; customer values win on conflict with our hardcoded defaults. Lets customers add provider-specific fields (`top_p`, `max_completion_tokens`) or override values like `temperature` for providers that reject our defaults. + ### Changed ### Fixed diff --git a/docs/README.md b/docs/README.md index b3191dbd..9a0ca606 100644 --- a/docs/README.md +++ b/docs/README.md @@ -176,9 +176,12 @@ response = client.models.create_custom( name="My Fine-tuned Model", key="my-org/custom-model-v1", description="Fine-tuned GPT for medical Q&A", - api_url="https://my-api.example.com/v1", + api_url="https://my-api.example.com/v1/chat/completions", max_tokens=4096, api_key=os.environ.get("MY_PROVIDER_API_KEY"), # optional + # Optional — merged into every request body. Useful for provider-specific + # fields or for overriding our defaults (e.g. {"temperature": 1}). + extra_payload={"top_p": 0.9}, ) print(f"Created model: {response.model_id}") ``` diff --git a/docs/api-reference/models-benchmarks.md b/docs/api-reference/models-benchmarks.md index aeffd32e..22a773c3 100644 --- a/docs/api-reference/models-benchmarks.md +++ b/docs/api-reference/models-benchmarks.md @@ -143,21 +143,28 @@ client = Stratix() success = client.models.remove("model-id-1", "model-id-2") ``` -### `create_custom(name, key, description, api_url, max_tokens, api_key=None, timeout=None)` +### `create_custom(name, key, description, api_url, max_tokens, api_key=None, extra_payload=None, timeout=None)` Creates a custom model backed by an OpenAI-compatible API endpoint. This allows you to evaluate any model accessible via a chat completions endpoint. #### Parameters -| Parameter | Type | Required | Description | -| ------------- | -------------------------------- | -------- | --------------------------------------------------------------------------------- | -| `name` | `str` | Yes | Model name (max 256 characters) | -| `key` | `str` | Yes | Unique model key, lowercase alphanumeric with dots/hyphens/slashes (max 256 chars)| -| `description` | `str` | Yes | Model description (max 500 characters) | -| `api_url` | `str` | Yes | Base URL of the OpenAI-compatible API endpoint | -| `max_tokens` | `int` | Yes | Maximum number of tokens the model supports | -| `api_key` | `str \| None` | No | API key for the model provider | -| `timeout` | `float \| httpx.Timeout \| None` | No | Override request timeout | +| Parameter | Type | Required | Description | +| --------------- | --------------------------------- | -------- | --------------------------------------------------------------------------------- | +| `name` | `str` | Yes | Model name (max 256 characters) | +| `key` | `str` | Yes | Unique model key, lowercase alphanumeric with dots/hyphens/slashes (max 256 chars)| +| `description` | `str` | Yes | Model description (max 500 characters) | +| `api_url` | `str` | Yes | Full URL of the OpenAI-compatible chat completions endpoint | +| `max_tokens` | `int` | Yes | Maximum number of tokens the model supports | +| `api_key` | `str \| None` | No | API key for the model provider | +| `extra_payload` | `Dict[str, Any] \| None` | No | JSON object merged into every outgoing chat-completions request body (see below) | +| `timeout` | `float \| httpx.Timeout \| None` | No | Override request timeout | + +#### `extra_payload` semantics + +When set, the keys/values in `extra_payload` are deep-merged into every outgoing request body. Customer values **win on conflict** with our hardcoded defaults — use it to override `temperature` (we send `0` for reproducible evaluations) or to add provider-specific fields like `top_p`, `presence_penalty`, or `max_completion_tokens` (required by some OpenAI reasoning models that reject `max_tokens`). + +The keys `messages`, `model`, and `stream` are reserved and will be rejected. #### Returns @@ -178,28 +185,31 @@ result = client.models.create_custom( name="My Custom Model", key="my-org/custom-model-v1", description="Custom fine-tuned model served via vLLM", - api_url="https://my-model-endpoint.example.com/v1", + api_url="https://my-model-endpoint.example.com/v1/chat/completions", api_key="my-provider-api-key", max_tokens=4096, + # Optional — provider-specific overrides merged into every request body. + extra_payload={"top_p": 0.9}, ) if result: print(f"Created model: {result.model_id}") ``` -### `update_custom(model_id, *, api_url=None, api_key=None, max_tokens=None, timeout=None)` +### `update_custom(model_id, *, api_url=None, api_key=None, max_tokens=None, extra_payload=None, timeout=None)` -Updates a custom model's mutable fields. At least one of `api_url`, `api_key`, or `max_tokens` must be provided. Primary use case: repointing `api_url` for ephemeral vLLM endpoints behind cloudflared tunnels whose URL changes between sessions. +Updates a custom model's mutable fields. At least one of `api_url`, `api_key`, `max_tokens`, or `extra_payload` must be provided. Primary use case: repointing `api_url` for ephemeral vLLM endpoints behind cloudflared tunnels whose URL changes between sessions. #### Parameters -| Parameter | Type | Required | Description | -| ------------ | -------------------------------- | -------- | -------------------------------------------------------- | -| `model_id` | `str` | Yes | ID of the custom model to update | -| `api_url` | `str \| None` | No | New base URL for the OpenAI-compatible API endpoint | -| `api_key` | `str \| None` | No | New API key for the model provider | -| `max_tokens` | `int \| None` | No | New maximum tokens value | -| `timeout` | `float \| httpx.Timeout \| None` | No | Override request timeout | +| Parameter | Type | Required | Description | +| --------------- | --------------------------------- | -------- | -------------------------------------------------------------------------------- | +| `model_id` | `str` | Yes | ID of the custom model to update | +| `api_url` | `str \| None` | No | New full URL of the OpenAI-compatible chat completions endpoint | +| `api_key` | `str \| None` | No | New API key for the model provider | +| `max_tokens` | `int \| None` | No | New maximum tokens value | +| `extra_payload` | `Dict[str, Any] \| None` | No | New JSON object merged into every outgoing request. Pass `{}` to clear it. | +| `timeout` | `float \| httpx.Timeout \| None` | No | Override request timeout | #### Returns @@ -213,7 +223,13 @@ client = Stratix() # Repoint the api_url without re-creating the model client.models.update_custom( "model-id-from-create-custom", - api_url="https://my-new-endpoint.example.com/v1", + api_url="https://my-new-endpoint.example.com/v1/chat/completions", +) + +# Override request parameters for a model that doesn't accept temperature=0 +client.models.update_custom( + "model-id-from-create-custom", + extra_payload={"temperature": 1}, ) ``` diff --git a/docs/examples/models-and-benchmarks.md b/docs/examples/models-and-benchmarks.md index e517344f..fa67154c 100644 --- a/docs/examples/models-and-benchmarks.md +++ b/docs/examples/models-and-benchmarks.md @@ -115,7 +115,7 @@ def main(): name="My Custom Model", key="my-org/custom-model-v1", description="Custom fine-tuned model served via vLLM", - api_url="https://my-model-endpoint.example.com/v1", + api_url="https://my-model-endpoint.example.com/v1/chat/completions", api_key=os.environ["MY_PROVIDER_API_KEY"], max_tokens=4096, ) @@ -152,7 +152,7 @@ def main(): name="My Tunnel-backed Model", key="my-org/tunnel-model-v1", description="vLLM served behind a cloudflared tunnel", - api_url="https://tunnel-1.example.com/v1", + api_url="https://tunnel-1.example.com/v1/chat/completions", api_key="my-provider-api-key", max_tokens=4096, ) @@ -161,7 +161,7 @@ def main(): # Later, when the tunnel URL changes: client.models.update_custom( result.model_id, - api_url="https://tunnel-2.example.com/v1", + api_url="https://tunnel-2.example.com/v1/chat/completions", ) # Run evaluations as usual — the model now points at the new endpoint. @@ -190,7 +190,7 @@ def main(): name="My Custom Model", key="my-org/custom-model-v2", description="Replacement after schema migration", - api_url="https://my-endpoint.example.com/v1", + api_url="https://my-endpoint.example.com/v1/chat/completions", api_key="my-provider-api-key", max_tokens=4096, ) diff --git a/samples/claude-code/skills/benchmark.md b/samples/claude-code/skills/benchmark.md index 7926da6a..8083727c 100644 --- a/samples/claude-code/skills/benchmark.md +++ b/samples/claude-code/skills/benchmark.md @@ -38,7 +38,7 @@ model = client.models.create_custom( name="My Custom Model", key="my-custom-model", description="Fine-tuned GPT for legal analysis", - api_url="https://api.example.com/v1/completions", + api_url="https://api.example.com/v1/chat/completions", max_tokens=4096, api_key="sk-...", ) diff --git a/samples/core/custom_model.py b/samples/core/custom_model.py index e660fb04..6ff83ec8 100644 --- a/samples/core/custom_model.py +++ b/samples/core/custom_model.py @@ -39,9 +39,14 @@ def main() -> None: name="My Custom Model", key="my-org/custom-model-v1", description="Custom fine-tuned model served via vLLM", - api_url="https://my-model-endpoint.example.com/v1", + api_url="https://my-model-endpoint.example.com/v1/chat/completions", api_key="my-provider-api-key", max_tokens=4096, + # Optional -- merged into every outgoing request body. Customer + # values win on conflict with our hardcoded defaults (we send + # `temperature: 0` for reproducible evals; override here for + # providers that reject it, e.g. {"temperature": 1}). + extra_payload={"top_p": 0.9}, ) if result: @@ -69,7 +74,7 @@ def main() -> None: updated = client.models.update_custom( result.model_id, - api_url="https://my-new-endpoint.example.com/v1", + api_url="https://my-new-endpoint.example.com/v1/chat/completions", ) if updated: print(f"\nCustom model {result.model_id} api_url updated") diff --git a/src/layerlens/resources/models/models.py b/src/layerlens/resources/models/models.py index 30ad5579..f29c2a97 100644 --- a/src/layerlens/resources/models/models.py +++ b/src/layerlens/resources/models/models.py @@ -220,6 +220,7 @@ def create_custom( api_url: str, max_tokens: int, api_key: Optional[str] = None, + extra_payload: Optional[Dict[str, Any]] = None, timeout: float | httpx.Timeout | None = DEFAULT_TIMEOUT, ) -> Optional[CreateModelResponse]: """Create a custom model backed by an OpenAI-compatible API. @@ -231,6 +232,11 @@ def create_custom( api_url: Base URL of the OpenAI-compatible API endpoint. max_tokens: Maximum number of tokens the model supports. api_key: Optional API key for the model provider. + extra_payload: Optional JSON object merged into every outgoing + chat-completions request body. Customer values win on conflict + with our defaults (e.g. set ``{"temperature": 1}`` for + providers that reject ``temperature: 0``). Keys ``messages``, + ``model`` and ``stream`` are reserved. timeout: Request timeout override. Returns: @@ -246,6 +252,8 @@ def create_custom( } if api_key is not None: body["api_key"] = api_key + if extra_payload is not None: + body["extra_payload"] = extra_payload resp = self._post( f"{base}/custom-models", @@ -266,12 +274,13 @@ def update_custom( api_url: Optional[str] = None, api_key: Optional[str] = None, max_tokens: Optional[int] = None, + extra_payload: Optional[Dict[str, Any]] = None, timeout: float | httpx.Timeout | None = DEFAULT_TIMEOUT, ) -> bool: """Update a custom model's mutable fields. - At least one of ``api_url``, ``api_key``, or ``max_tokens`` must be - provided. Returns ``True`` on success. + At least one of ``api_url``, ``api_key``, ``max_tokens`` or + ``extra_payload`` must be provided. Returns ``True`` on success. Primary use case: repointing ``api_url`` for ephemeral vLLM endpoints behind cloudflared tunnels whose URL changes between sessions. @@ -281,6 +290,9 @@ def update_custom( api_url: New base URL for the OpenAI-compatible API endpoint. api_key: New API key for the model provider. max_tokens: New maximum tokens value. + extra_payload: New JSON object merged into every outgoing request + body. Pass ``{}`` to clear the existing payload. See + ``create_custom`` for semantics. timeout: Request timeout override. """ url = ( @@ -293,6 +305,8 @@ def update_custom( body["api_key"] = api_key if max_tokens is not None: body["max_tokens"] = max_tokens + if extra_payload is not None: + body["extra_payload"] = extra_payload resp = self._patch(url, body=body, timeout=timeout, cast_to=dict) return isinstance(resp, dict) and "data" in resp @@ -477,6 +491,7 @@ async def create_custom( api_url: str, max_tokens: int, api_key: Optional[str] = None, + extra_payload: Optional[Dict[str, Any]] = None, timeout: float | httpx.Timeout | None = DEFAULT_TIMEOUT, ) -> Optional[CreateModelResponse]: """Create a custom model backed by an OpenAI-compatible API. @@ -488,6 +503,11 @@ async def create_custom( api_url: Base URL of the OpenAI-compatible API endpoint. max_tokens: Maximum number of tokens the model supports. api_key: Optional API key for the model provider. + extra_payload: Optional JSON object merged into every outgoing + chat-completions request body. Customer values win on conflict + with our defaults (e.g. set ``{"temperature": 1}`` for + providers that reject ``temperature: 0``). Keys ``messages``, + ``model`` and ``stream`` are reserved. timeout: Request timeout override. Returns: @@ -503,6 +523,8 @@ async def create_custom( } if api_key is not None: body["api_key"] = api_key + if extra_payload is not None: + body["extra_payload"] = extra_payload resp = await self._post( f"{base}/custom-models", @@ -523,12 +545,23 @@ async def update_custom( api_url: Optional[str] = None, api_key: Optional[str] = None, max_tokens: Optional[int] = None, + extra_payload: Optional[Dict[str, Any]] = None, timeout: float | httpx.Timeout | None = DEFAULT_TIMEOUT, ) -> bool: """Update a custom model's mutable fields. - At least one of ``api_url``, ``api_key``, or ``max_tokens`` must be - provided. Returns ``True`` on success. + At least one of ``api_url``, ``api_key``, ``max_tokens`` or + ``extra_payload`` must be provided. Returns ``True`` on success. + + Args: + model_id: ID of the custom model to update. + api_url: New base URL for the OpenAI-compatible API endpoint. + api_key: New API key for the model provider. + max_tokens: New maximum tokens value. + extra_payload: New JSON object merged into every outgoing request + body. Pass ``{}`` to clear the existing payload. See + ``create_custom`` for semantics. + timeout: Request timeout override. """ url = ( f"/organizations/{self._client.organization_id}/projects/{self._client.project_id}/custom-models/{model_id}" @@ -540,6 +573,8 @@ async def update_custom( body["api_key"] = api_key if max_tokens is not None: body["max_tokens"] = max_tokens + if extra_payload is not None: + body["extra_payload"] = extra_payload resp = await self._patch(url, body=body, timeout=timeout, cast_to=dict) return isinstance(resp, dict) and "data" in resp From 25d2dc38d4e7281278218ef672953710ee8ba7c4 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Tue, 19 May 2026 16:31:36 -0300 Subject: [PATCH 2/4] test(models): cover extra_payload in create_custom / update_custom Five new cases exercising the new parameter: - create_custom forwards extra_payload verbatim - create_custom omits the key when None - update_custom supports extra_payload-only updates - update_custom({}) sends an empty dict so the backend clears the stored payload (semantics added in atlas-app#1932) - update_custom omits the key when None Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/resources/test_models_resource.py | 68 +++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/resources/test_models_resource.py b/tests/resources/test_models_resource.py index 6fbd4895..5f4c90fb 100644 --- a/tests/resources/test_models_resource.py +++ b/tests/resources/test_models_resource.py @@ -798,6 +798,44 @@ def test_create_custom_omits_api_key_when_none(self, models_resource): call_body = models_resource._post.call_args.kwargs["body"] assert "api_key" not in call_body + def test_create_custom_includes_extra_payload_when_provided(self, models_resource): + """create_custom() forwards extra_payload verbatim.""" + models_resource._post.return_value = { + "status": "success", + "data": {"model_id": "x", "organization_id": "o", "project_id": "p"}, + } + + payload = {"top_p": 0.9, "provider": {"order": ["anthropic"]}} + models_resource.create_custom( + name="My Model", + key="my/model", + description="desc", + api_url="https://example.com/v1/chat/completions", + max_tokens=4096, + extra_payload=payload, + ) + + call_body = models_resource._post.call_args.kwargs["body"] + assert call_body["extra_payload"] == payload + + def test_create_custom_omits_extra_payload_when_none(self, models_resource): + """create_custom() does not include extra_payload when not provided.""" + models_resource._post.return_value = { + "status": "success", + "data": {"model_id": "x", "organization_id": "o", "project_id": "p"}, + } + + models_resource.create_custom( + name="My Model", + key="my/model", + description="desc", + api_url="https://example.com/v1/chat/completions", + max_tokens=4096, + ) + + call_body = models_resource._post.call_args.kwargs["body"] + assert "extra_payload" not in call_body + def test_create_custom_correct_url(self, models_resource): """create_custom() posts to the correct endpoint.""" models_resource._post.return_value = { @@ -1208,6 +1246,36 @@ def test_update_custom_max_tokens_only(self, models_resource): body = models_resource._patch.call_args.kwargs["body"] assert body == {"max_tokens": 8192} + def test_update_custom_extra_payload_only(self, models_resource): + """update_custom() supports extra_payload-only updates.""" + models_resource._patch.return_value = {"data": {"id": "model-1"}} + + payload = {"temperature": 1, "top_p": 0.9} + result = models_resource.update_custom("model-1", extra_payload=payload) + + assert result is True + body = models_resource._patch.call_args.kwargs["body"] + assert body == {"extra_payload": payload} + + def test_update_custom_extra_payload_empty_dict_clears_payload(self, models_resource): + """update_custom(extra_payload={}) sends the empty dict so the backend clears the stored payload.""" + models_resource._patch.return_value = {"data": {"id": "model-1"}} + + result = models_resource.update_custom("model-1", extra_payload={}) + + assert result is True + body = models_resource._patch.call_args.kwargs["body"] + assert body == {"extra_payload": {}} + + def test_update_custom_omits_extra_payload_when_none(self, models_resource): + """update_custom() does not include extra_payload when not provided.""" + models_resource._patch.return_value = {"data": {"id": "model-1"}} + + models_resource.update_custom("model-1", api_url="https://x.io") + + body = models_resource._patch.call_args.kwargs["body"] + assert "extra_payload" not in body + def test_update_custom_returns_false_on_error_envelope(self, models_resource): """update_custom() returns False when response has no data field.""" models_resource._patch.return_value = {"code": "NOT_FOUND", "message": "missing"} From 59eed1789516de3cd70b849ef2a5d793623006fe Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Wed, 20 May 2026 09:32:50 -0300 Subject: [PATCH 3/4] chore: bump version to 1.6.2 Releases the ``extra_payload`` parameter added in the previous commits. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 10 +++++++--- src/layerlens/_version.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fe342d..a079a637 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to the Stratix Python SDK will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -**Latest version:** [1.6.1](https://github.com/LayerLens/stratix-python/releases/tag/v1.6.1) — 2026-05-15 +**Latest version:** [1.6.2](https://github.com/LayerLens/stratix-python/releases/tag/v1.6.2) — 2026-05-20 ## [Unreleased] @@ -13,8 +13,6 @@ Things we're actively working on. Want to help? Check the [issues](https://githu ### Added -- `extra_payload` parameter on `models.create_custom` and `models.update_custom` (sync + async). Optional JSON object merged into every outgoing chat-completions request body; customer values win on conflict with our hardcoded defaults. Lets customers add provider-specific fields (`top_p`, `max_completion_tokens`) or override values like `temperature` for providers that reject our defaults. - ### Changed ### Fixed @@ -23,6 +21,12 @@ Things we're actively working on. Want to help? Check the [issues](https://githu ### Removed +## [1.6.2] - 2026-05-20 + +### Added + +- `extra_payload` parameter on `models.create_custom` and `models.update_custom` (sync + async). Optional JSON object merged into every outgoing chat-completions request body; customer values win on conflict with our hardcoded defaults. Lets customers add provider-specific fields (`top_p`, `max_completion_tokens`) or override values like `temperature` for providers that reject our defaults. + ## [1.6.1] - 2026-05-15 ### Added diff --git a/src/layerlens/_version.py b/src/layerlens/_version.py index fb6b8f67..c4a6034c 100644 --- a/src/layerlens/_version.py +++ b/src/layerlens/_version.py @@ -1,4 +1,4 @@ -__version__ = "1.6.1" +__version__ = "1.6.2" # Will be templated during the build __git_commit__ = "__GIT_COMMIT__" From c2c436f7a23dc095288da159092f8a0d07e2278b Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Wed, 20 May 2026 09:51:09 -0300 Subject: [PATCH 4/4] chore: re-bump version to 1.7.0 The previous commit bumped to 1.6.2, but adding the new ``extra_payload`` parameter counts as new functionality, so the semver-correct minor bump is 1.7.0. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 4 ++-- src/layerlens/_version.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a079a637..8643f010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to the Stratix Python SDK will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -**Latest version:** [1.6.2](https://github.com/LayerLens/stratix-python/releases/tag/v1.6.2) — 2026-05-20 +**Latest version:** [1.7.0](https://github.com/LayerLens/stratix-python/releases/tag/v1.7.0) — 2026-05-20 ## [Unreleased] @@ -21,7 +21,7 @@ Things we're actively working on. Want to help? Check the [issues](https://githu ### Removed -## [1.6.2] - 2026-05-20 +## [1.7.0] - 2026-05-20 ### Added diff --git a/src/layerlens/_version.py b/src/layerlens/_version.py index c4a6034c..9ce8ca24 100644 --- a/src/layerlens/_version.py +++ b/src/layerlens/_version.py @@ -1,4 +1,4 @@ -__version__ = "1.6.2" +__version__ = "1.7.0" # Will be templated during the build __git_commit__ = "__GIT_COMMIT__"