diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index c4bf1b6c0..e72f11310 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.13.3"
+ ".": "1.14.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 379a3990c..b1a5e6c48 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 124
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-11588dad716c3ded3699f14d5e1c5f847d6d099ce0595430f608386b2d1d7c46.yml
-openapi_spec_hash: 60c33284c8248c346994db8b2b399758
-config_hash: a759c23a5a04ad26f8740acc7e094c01
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-f32de1991bef7651f9b0970b503e2986c7a88708c4a408d54abe6d089795e9f9.yml
+openapi_spec_hash: d2005d48f75fba4a5368209cf49641dc
+config_hash: 5ffcc19219880e7d9ce43c1e6860568c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac31ebc9c..70c9db0e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,32 @@
# Changelog
+## 1.14.0 (2026-03-31)
+
+Full Changelog: [v1.13.3...v1.14.0](https://github.com/runloopai/api-client-python/compare/v1.13.3...v1.14.0)
+
+### Features
+
+* add archive / unarchive to benchmarks ([#8391](https://github.com/runloopai/api-client-python/issues/8391)) ([31ebb2c](https://github.com/runloopai/api-client-python/commit/31ebb2cc196e185eaef2ee8d6ddcd3e04b0a6ece))
+* Add axon list filters by id and name ([#8384](https://github.com/runloopai/api-client-python/issues/8384)) ([cd722b3](https://github.com/runloopai/api-client-python/commit/cd722b341a528558a5736894aa27bab44aa4a06e))
+* Add pagination to list active axons ([#8359](https://github.com/runloopai/api-client-python/issues/8359)) ([1937bc9](https://github.com/runloopai/api-client-python/commit/1937bc9c660895d9355d37a1f052f00fde9128e1))
+* **internal:** implement indices array format for query and form serialization ([1239661](https://github.com/runloopai/api-client-python/commit/12396614f8151d5a244c6e91815665caa6cd4c1b))
+
+
+### Bug Fixes
+
+* **sdk:** expose axon list params ([#773](https://github.com/runloopai/api-client-python/issues/773)) ([47e208d](https://github.com/runloopai/api-client-python/commit/47e208d61c247719174f5c0625803355114fa773))
+* **tests:** poll for logs in smoke tests to handle CloudWatch ingestion latency ([#774](https://github.com/runloopai/api-client-python/issues/774)) ([5f1e187](https://github.com/runloopai/api-client-python/commit/5f1e18703bd18370d1f63d7bbb2f6a22716624ff))
+
+
+### Chores
+
+* **axon:** add axon auto-pagination to stainless sdks ([#8420](https://github.com/runloopai/api-client-python/issues/8420)) ([14806e1](https://github.com/runloopai/api-client-python/commit/14806e18b4b8d2164ee8db80ebe62f853f7885bf))
+
+
+### Documentation
+
+* **api:** document vCPU, RAM, and disk for resource_size_request ([#8368](https://github.com/runloopai/api-client-python/issues/8368)) ([1edfb84](https://github.com/runloopai/api-client-python/commit/1edfb840f46ac3295ef097a7574eecb809e2f1d5))
+
## 1.13.3 (2026-03-26)
Full Changelog: [v1.13.2...v1.13.3](https://github.com/runloopai/api-client-python/compare/v1.13.2...v1.13.3)
diff --git a/api.md b/api.md
index 239d793fb..14d010381 100644
--- a/api.md
+++ b/api.md
@@ -107,7 +107,7 @@ Methods:
- client.axons.create(\*\*params) -> AxonView
- client.axons.retrieve(id) -> AxonView
-- client.axons.list() -> AxonListView
+- client.axons.list(\*\*params) -> SyncAxonsCursorIDPage[AxonView]
- client.axons.publish(id, \*\*params) -> PublishResultView
- client.axons.subscribe_sse(id) -> AxonEventView
diff --git a/pyproject.toml b/pyproject.toml
index 0eff0cd53..93bd1ad77 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
-version = "1.13.3"
+version = "1.14.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
diff --git a/scripts/mock b/scripts/mock
index 09eb49f65..290e21b9a 100755
--- a/scripts/mock
+++ b/scripts/mock
@@ -24,7 +24,7 @@ if [ "$1" == "--daemon" ]; then
# Pre-install the package so the download doesn't eat into the startup timeout
npm exec --package=@stdy/cli@0.19.7 -- steady --version
- npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log &
+ npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log &
# Wait for server to come online via health endpoint (max 30s)
echo -n "Waiting for server"
@@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then
echo
else
- npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL"
+ npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL"
fi
diff --git a/scripts/test b/scripts/test
index 10fadae13..a631738f5 100755
--- a/scripts/test
+++ b/scripts/test
@@ -43,7 +43,7 @@ elif ! steady_is_running ; then
echo -e "To run the server, pass in the path or url of your OpenAPI"
echo -e "spec to the steady command:"
echo
- echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=comma --validator-query-array-format=comma --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}"
+ echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}"
echo
exit 1
diff --git a/src/runloop_api_client/_qs.py b/src/runloop_api_client/_qs.py
index ada6fd3f7..de8c99bc6 100644
--- a/src/runloop_api_client/_qs.py
+++ b/src/runloop_api_client/_qs.py
@@ -101,7 +101,10 @@ def _stringify_item(
items.extend(self._stringify_item(key, item, opts))
return items
elif array_format == "indices":
- raise NotImplementedError("The array indices format is not supported yet")
+ items = []
+ for i, item in enumerate(value):
+ items.extend(self._stringify_item(f"{key}[{i}]", item, opts))
+ return items
elif array_format == "brackets":
items = []
key = key + "[]"
diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py
index a9339227a..51ea16bb5 100644
--- a/src/runloop_api_client/_version.py
+++ b/src/runloop_api_client/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "runloop_api_client"
-__version__ = "1.13.3" # x-release-please-version
+__version__ = "1.14.0" # x-release-please-version
diff --git a/src/runloop_api_client/pagination.py b/src/runloop_api_client/pagination.py
index e084ef68e..9d1fd9491 100644
--- a/src/runloop_api_client/pagination.py
+++ b/src/runloop_api_client/pagination.py
@@ -18,6 +18,8 @@
"AsyncBenchmarksCursorIDPage",
"SyncAgentsCursorIDPage",
"AsyncAgentsCursorIDPage",
+ "SyncAxonsCursorIDPage",
+ "AsyncAxonsCursorIDPage",
"SyncBenchmarkRunsCursorIDPage",
"AsyncBenchmarkRunsCursorIDPage",
"SyncScenariosCursorIDPage",
@@ -69,6 +71,11 @@ class AgentsCursorIDPageItem(Protocol):
id: str
+@runtime_checkable
+class AxonsCursorIDPageItem(Protocol):
+ id: str
+
+
@runtime_checkable
class BenchmarkRunsCursorIDPageItem(Protocol):
id: str
@@ -517,6 +524,74 @@ def next_page_info(self) -> Optional[PageInfo]:
return PageInfo(params={"starting_after": item.id})
+class SyncAxonsCursorIDPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
+ axons: List[_T]
+ has_more: Optional[bool] = None
+ total_count: Optional[int] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ axons = self.axons
+ if not axons:
+ return []
+ return axons
+
+ @override
+ def has_next_page(self) -> bool:
+ has_more = self.has_more
+ if has_more is not None and has_more is False:
+ return False
+
+ return super().has_next_page()
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ axons = self.axons
+ if not axons:
+ return None
+
+ item = cast(Any, axons[-1])
+ if not isinstance(item, AxonsCursorIDPageItem) or item.id is None: # pyright: ignore[reportUnnecessaryComparison]
+ # TODO emit warning log
+ return None
+
+ return PageInfo(params={"starting_after": item.id})
+
+
+class AsyncAxonsCursorIDPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
+ axons: List[_T]
+ has_more: Optional[bool] = None
+ total_count: Optional[int] = None
+
+ @override
+ def _get_page_items(self) -> List[_T]:
+ axons = self.axons
+ if not axons:
+ return []
+ return axons
+
+ @override
+ def has_next_page(self) -> bool:
+ has_more = self.has_more
+ if has_more is not None and has_more is False:
+ return False
+
+ return super().has_next_page()
+
+ @override
+ def next_page_info(self) -> Optional[PageInfo]:
+ axons = self.axons
+ if not axons:
+ return None
+
+ item = cast(Any, axons[-1])
+ if not isinstance(item, AxonsCursorIDPageItem) or item.id is None: # pyright: ignore[reportUnnecessaryComparison]
+ # TODO emit warning log
+ return None
+
+ return PageInfo(params={"starting_after": item.id})
+
+
class SyncBenchmarkRunsCursorIDPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
runs: List[_T]
has_more: Optional[bool] = None
diff --git a/src/runloop_api_client/resources/axons/axons.py b/src/runloop_api_client/resources/axons/axons.py
index 097fe2330..54f4cb9ff 100644
--- a/src/runloop_api_client/resources/axons/axons.py
+++ b/src/runloop_api_client/resources/axons/axons.py
@@ -15,7 +15,7 @@
SqlResourceWithStreamingResponse,
AsyncSqlResourceWithStreamingResponse,
)
-from ...types import axon_create_params, axon_publish_params
+from ...types import axon_list_params, axon_create_params, axon_publish_params
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
@@ -27,9 +27,9 @@
async_to_streamed_response_wrapper,
)
from ..._streaming import Stream, AsyncStream
-from ..._base_client import make_request_options
+from ...pagination import SyncAxonsCursorIDPage, AsyncAxonsCursorIDPage
+from ..._base_client import AsyncPaginator, make_request_options
from ...types.axon_view import AxonView
-from ...types.axon_list_view import AxonListView
from ...types.axon_event_view import AxonEventView
from ...types.publish_result_view import PublishResultView
@@ -137,20 +137,61 @@ def retrieve(
def list(
self,
*,
+ id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
+ limit: int | Omit = omit,
+ name: str | Omit = omit,
+ starting_after: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AxonListView:
- """[Beta] List all active axons."""
- return self._get(
+ ) -> SyncAxonsCursorIDPage[AxonView]:
+ """
+ [Beta] List all active axons.
+
+ Args:
+ id: Filter by axon ID.
+
+ include_total_count: If true (default), includes total_count in the response. Set to false to skip
+ the count query for better performance on large datasets.
+
+ limit: The limit of items to return. Default is 20. Max is 5000.
+
+ name: Filter by axon name (prefix match supported).
+
+ starting_after: Load the next page of data starting after the item with the given ID.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/v1/axons",
+ page=SyncAxonsCursorIDPage[AxonView],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "id": id,
+ "include_total_count": include_total_count,
+ "limit": limit,
+ "name": name,
+ "starting_after": starting_after,
+ },
+ axon_list_params.AxonListParams,
+ ),
),
- cast_to=AxonListView,
+ model=AxonView,
)
def publish(
@@ -350,23 +391,64 @@ async def retrieve(
cast_to=AxonView,
)
- async def list(
+ def list(
self,
*,
+ id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
+ limit: int | Omit = omit,
+ name: str | Omit = omit,
+ starting_after: str | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> AxonListView:
- """[Beta] List all active axons."""
- return await self._get(
+ ) -> AsyncPaginator[AxonView, AsyncAxonsCursorIDPage[AxonView]]:
+ """
+ [Beta] List all active axons.
+
+ Args:
+ id: Filter by axon ID.
+
+ include_total_count: If true (default), includes total_count in the response. Set to false to skip
+ the count query for better performance on large datasets.
+
+ limit: The limit of items to return. Default is 20. Max is 5000.
+
+ name: Filter by axon name (prefix match supported).
+
+ starting_after: Load the next page of data starting after the item with the given ID.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ return self._get_api_list(
"/v1/axons",
+ page=AsyncAxonsCursorIDPage[AxonView],
options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "id": id,
+ "include_total_count": include_total_count,
+ "limit": limit,
+ "name": name,
+ "starting_after": starting_after,
+ },
+ axon_list_params.AxonListParams,
+ ),
),
- cast_to=AxonListView,
+ model=AxonView,
)
async def publish(
diff --git a/src/runloop_api_client/resources/devboxes/devboxes.py b/src/runloop_api_client/resources/devboxes/devboxes.py
index 1f016f2eb..3e46b17b6 100644
--- a/src/runloop_api_client/resources/devboxes/devboxes.py
+++ b/src/runloop_api_client/resources/devboxes/devboxes.py
@@ -761,6 +761,7 @@ def enable_tunnel(
*,
auth_mode: Optional[Literal["open", "authenticated"]] | Omit = omit,
http_keep_alive: Optional[bool] | Omit = omit,
+ wake_on_http: Optional[bool] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -783,6 +784,9 @@ def enable_tunnel(
http_keep_alive: When true, HTTP traffic through the tunnel counts as activity for idle lifecycle
policies, resetting the idle timer. Defaults to true if not specified.
+ wake_on_http: When true, HTTP traffic to a suspended devbox will automatically trigger a
+ resume. Defaults to false if not specified.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -801,6 +805,7 @@ def enable_tunnel(
{
"auth_mode": auth_mode,
"http_keep_alive": http_keep_alive,
+ "wake_on_http": wake_on_http,
},
devbox_enable_tunnel_params.DevboxEnableTunnelParams,
),
@@ -2397,6 +2402,7 @@ async def enable_tunnel(
*,
auth_mode: Optional[Literal["open", "authenticated"]] | Omit = omit,
http_keep_alive: Optional[bool] | Omit = omit,
+ wake_on_http: Optional[bool] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -2419,6 +2425,9 @@ async def enable_tunnel(
http_keep_alive: When true, HTTP traffic through the tunnel counts as activity for idle lifecycle
policies, resetting the idle timer. Defaults to true if not specified.
+ wake_on_http: When true, HTTP traffic to a suspended devbox will automatically trigger a
+ resume. Defaults to false if not specified.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -2437,6 +2446,7 @@ async def enable_tunnel(
{
"auth_mode": auth_mode,
"http_keep_alive": http_keep_alive,
+ "wake_on_http": wake_on_http,
},
devbox_enable_tunnel_params.DevboxEnableTunnelParams,
),
diff --git a/src/runloop_api_client/sdk/_types.py b/src/runloop_api_client/sdk/_types.py
index aa7e0208a..4d2accc46 100644
--- a/src/runloop_api_client/sdk/_types.py
+++ b/src/runloop_api_client/sdk/_types.py
@@ -4,6 +4,7 @@
from ..types import (
InputContext,
ScenarioView,
+ AxonListParams,
AgentListParams,
AxonCreateParams,
DevboxListParams,
@@ -190,6 +191,10 @@ class SDKAgentListParams(AgentListParams, BaseRequestOptions):
pass
+class SDKAxonListParams(AxonListParams, BaseRequestOptions):
+ pass
+
+
class SDKAxonCreateParams(AxonCreateParams, LongRequestOptions):
pass
diff --git a/src/runloop_api_client/sdk/async_.py b/src/runloop_api_client/sdk/async_.py
index c2a237da8..d02a6a9f1 100644
--- a/src/runloop_api_client/sdk/async_.py
+++ b/src/runloop_api_client/sdk/async_.py
@@ -11,6 +11,7 @@
import httpx
from ._types import (
+ SDKAxonListParams,
BaseRequestOptions,
LongRequestOptions,
SDKAgentListParams,
@@ -544,9 +545,14 @@ def from_id(self, axon_id: str) -> AsyncAxon:
"""Get an AsyncAxon instance for an existing axon ID."""
return AsyncAxon(self._client, axon_id)
- async def list(self, **options: Unpack[BaseRequestOptions]) -> list[AsyncAxon]:
- """[Beta] List all active axons."""
- result = await self._client.axons.list(**options)
+ async def list(self, **params: Unpack[SDKAxonListParams]) -> list[AsyncAxon]:
+ """[Beta] List all active axons.
+
+ :param params: See :typeddict:`~runloop_api_client.sdk._types.SDKAxonListParams` for available parameters
+ :return: Collection of axon wrappers
+ :rtype: list[AsyncAxon]
+ """
+ result = await self._client.axons.list(**params)
return [AsyncAxon(self._client, axon.id) for axon in result.axons]
diff --git a/src/runloop_api_client/sdk/sync.py b/src/runloop_api_client/sdk/sync.py
index 0fa9f8cea..e6b672159 100644
--- a/src/runloop_api_client/sdk/sync.py
+++ b/src/runloop_api_client/sdk/sync.py
@@ -12,6 +12,7 @@
from .axon import Axon
from .agent import Agent
from ._types import (
+ SDKAxonListParams,
BaseRequestOptions,
LongRequestOptions,
SDKAgentListParams,
@@ -539,9 +540,14 @@ def from_id(self, axon_id: str) -> Axon:
"""Get an Axon instance for an existing axon ID."""
return Axon(self._client, axon_id)
- def list(self, **options: Unpack[BaseRequestOptions]) -> list[Axon]:
- """[Beta] List all active axons."""
- result = self._client.axons.list(**options)
+ def list(self, **params: Unpack[SDKAxonListParams]) -> list[Axon]:
+ """[Beta] List all active axons.
+
+ :param params: See :typeddict:`~runloop_api_client.sdk._types.SDKAxonListParams` for available parameters
+ :return: Collection of axon wrappers
+ :rtype: list[Axon]
+ """
+ result = self._client.axons.list(**params)
return [Axon(self._client, axon.id) for axon in result.axons]
diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py
index 77ac06e96..bf5d8ef3f 100644
--- a/src/runloop_api_client/types/__init__.py
+++ b/src/runloop_api_client/types/__init__.py
@@ -27,6 +27,7 @@
from .agent_list_view import AgentListView as AgentListView
from .axon_event_view import AxonEventView as AxonEventView
from .mcp_config_view import McpConfigView as McpConfigView
+from .axon_list_params import AxonListParams as AxonListParams
from .devbox_list_view import DevboxListView as DevboxListView
from .object_list_view import ObjectListView as ObjectListView
from .scoring_contract import ScoringContract as ScoringContract
diff --git a/src/runloop_api_client/types/axon_list_params.py b/src/runloop_api_client/types/axon_list_params.py
new file mode 100644
index 000000000..dbe4cdb80
--- /dev/null
+++ b/src/runloop_api_client/types/axon_list_params.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import TypedDict
+
+__all__ = ["AxonListParams"]
+
+
+class AxonListParams(TypedDict, total=False):
+ id: str
+ """Filter by axon ID."""
+
+ include_total_count: bool
+ """If true (default), includes total_count in the response.
+
+ Set to false to skip the count query for better performance on large datasets.
+ """
+
+ limit: int
+ """The limit of items to return. Default is 20. Max is 5000."""
+
+ name: str
+ """Filter by axon name (prefix match supported)."""
+
+ starting_after: str
+ """Load the next page of data starting after the item with the given ID."""
diff --git a/src/runloop_api_client/types/axon_list_view.py b/src/runloop_api_client/types/axon_list_view.py
index bd6c4d31c..4bd0bef08 100644
--- a/src/runloop_api_client/types/axon_list_view.py
+++ b/src/runloop_api_client/types/axon_list_view.py
@@ -1,6 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-from typing import List
+from typing import List, Optional
from .._models import BaseModel
from .axon_view import AxonView
@@ -11,3 +11,7 @@
class AxonListView(BaseModel):
axons: List[AxonView]
"""List of active axons."""
+
+ has_more: bool
+
+ total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/benchmark_view.py b/src/runloop_api_client/types/benchmark_view.py
index 4150847ac..1eb52fb6e 100644
--- a/src/runloop_api_client/types/benchmark_view.py
+++ b/src/runloop_api_client/types/benchmark_view.py
@@ -1,6 +1,7 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Dict, List, Optional
+from typing_extensions import Literal
from pydantic import Field as FieldInfo
@@ -26,6 +27,12 @@ class BenchmarkView(BaseModel):
scenario_ids: List[str] = FieldInfo(alias="scenarioIds")
"""List of Scenario IDs that make up the benchmark."""
+ status: Literal["active", "archived"]
+ """Whether the benchmark is active or archived.
+
+ Archived benchmarks are excluded from listings and cannot be run.
+ """
+
attribution: Optional[str] = None
"""Attribution information for the benchmark."""
diff --git a/src/runloop_api_client/types/devbox_create_params.py b/src/runloop_api_client/types/devbox_create_params.py
index c72820259..1b41796b2 100644
--- a/src/runloop_api_client/types/devbox_create_params.py
+++ b/src/runloop_api_client/types/devbox_create_params.py
@@ -149,3 +149,9 @@ class Tunnel(TypedDict, total=False):
When true, HTTP traffic through the tunnel counts as activity for idle lifecycle
policies, resetting the idle timer. Defaults to true if not specified.
"""
+
+ wake_on_http: Optional[bool]
+ """
+ When true, HTTP traffic to a suspended devbox will automatically trigger a
+ resume. Defaults to false if not specified.
+ """
diff --git a/src/runloop_api_client/types/devbox_enable_tunnel_params.py b/src/runloop_api_client/types/devbox_enable_tunnel_params.py
index 4906c85ef..cd380ebb4 100644
--- a/src/runloop_api_client/types/devbox_enable_tunnel_params.py
+++ b/src/runloop_api_client/types/devbox_enable_tunnel_params.py
@@ -17,3 +17,9 @@ class DevboxEnableTunnelParams(TypedDict, total=False):
When true, HTTP traffic through the tunnel counts as activity for idle lifecycle
policies, resetting the idle timer. Defaults to true if not specified.
"""
+
+ wake_on_http: Optional[bool]
+ """
+ When true, HTTP traffic to a suspended devbox will automatically trigger a
+ resume. Defaults to false if not specified.
+ """
diff --git a/src/runloop_api_client/types/shared/launch_parameters.py b/src/runloop_api_client/types/shared/launch_parameters.py
index 7c1fdc2a7..f882691e0 100644
--- a/src/runloop_api_client/types/shared/launch_parameters.py
+++ b/src/runloop_api_client/types/shared/launch_parameters.py
@@ -76,7 +76,14 @@ class LaunchParameters(BaseModel):
resource_size_request: Optional[
Literal["X_SMALL", "SMALL", "MEDIUM", "LARGE", "X_LARGE", "XX_LARGE", "CUSTOM_SIZE"]
] = None
- """Manual resource configuration for Devbox. If not set, defaults will be used."""
+ """Preset Devbox resources (vCPU, RAM in GiB, ephemeral disk in GiB).
+
+ If not set, SMALL is used. X_SMALL: 0.5 vCPU, 1 GiB RAM, 4 GiB disk. SMALL: 1
+ vCPU, 2 GiB RAM, 4 GiB disk. MEDIUM: 2 vCPU, 4 GiB RAM, 8 GiB disk. LARGE: 2
+ vCPU, 8 GiB RAM, 16 GiB disk. X_LARGE: 4 vCPU, 16 GiB RAM, 16 GiB disk.
+ XX_LARGE: 8 vCPU, 32 GiB RAM, 16 GiB disk. CUSTOM_SIZE: set custom_cpu_cores,
+ custom_gb_memory, and optionally custom_disk_size.
+ """
user_parameters: Optional[UserParameters] = None
"""Specify the user for execution on Devbox.
diff --git a/src/runloop_api_client/types/shared_params/launch_parameters.py b/src/runloop_api_client/types/shared_params/launch_parameters.py
index c30f90d86..65babd117 100644
--- a/src/runloop_api_client/types/shared_params/launch_parameters.py
+++ b/src/runloop_api_client/types/shared_params/launch_parameters.py
@@ -78,7 +78,14 @@ class LaunchParameters(TypedDict, total=False):
resource_size_request: Optional[
Literal["X_SMALL", "SMALL", "MEDIUM", "LARGE", "X_LARGE", "XX_LARGE", "CUSTOM_SIZE"]
]
- """Manual resource configuration for Devbox. If not set, defaults will be used."""
+ """Preset Devbox resources (vCPU, RAM in GiB, ephemeral disk in GiB).
+
+ If not set, SMALL is used. X_SMALL: 0.5 vCPU, 1 GiB RAM, 4 GiB disk. SMALL: 1
+ vCPU, 2 GiB RAM, 4 GiB disk. MEDIUM: 2 vCPU, 4 GiB RAM, 8 GiB disk. LARGE: 2
+ vCPU, 8 GiB RAM, 16 GiB disk. X_LARGE: 4 vCPU, 16 GiB RAM, 16 GiB disk.
+ XX_LARGE: 8 vCPU, 32 GiB RAM, 16 GiB disk. CUSTOM_SIZE: set custom_cpu_cores,
+ custom_gb_memory, and optionally custom_disk_size.
+ """
user_parameters: Optional[UserParameters]
"""Specify the user for execution on Devbox.
diff --git a/src/runloop_api_client/types/tunnel_view.py b/src/runloop_api_client/types/tunnel_view.py
index 9287cd4d2..6188968a0 100644
--- a/src/runloop_api_client/types/tunnel_view.py
+++ b/src/runloop_api_client/types/tunnel_view.py
@@ -33,6 +33,12 @@ class TunnelView(BaseModel):
URL format: https://{port}-{tunnel_key}.tunnel.runloop.{domain}
"""
+ wake_on_http: bool
+ """
+ When true, HTTP traffic to a suspended devbox will automatically trigger a
+ resume.
+ """
+
auth_token: Optional[str] = None
"""Bearer token for tunnel authentication.
diff --git a/tests/api_resources/test_axons.py b/tests/api_resources/test_axons.py
index bda5f1a23..ab076037a 100644
--- a/tests/api_resources/test_axons.py
+++ b/tests/api_resources/test_axons.py
@@ -9,7 +9,11 @@
from tests.utils import assert_matches_type
from runloop_api_client import Runloop, AsyncRunloop
-from runloop_api_client.types import AxonView, AxonListView, PublishResultView
+from runloop_api_client.types import (
+ AxonView,
+ PublishResultView,
+)
+from runloop_api_client.pagination import SyncAxonsCursorIDPage, AsyncAxonsCursorIDPage
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
@@ -90,7 +94,18 @@ def test_path_params_retrieve(self, client: Runloop) -> None:
@parametrize
def test_method_list(self, client: Runloop) -> None:
axon = client.axons.list()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(SyncAxonsCursorIDPage[AxonView], axon, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: Runloop) -> None:
+ axon = client.axons.list(
+ id="id",
+ include_total_count=True,
+ limit=0,
+ name="name",
+ starting_after="starting_after",
+ )
+ assert_matches_type(SyncAxonsCursorIDPage[AxonView], axon, path=["response"])
@parametrize
def test_raw_response_list(self, client: Runloop) -> None:
@@ -99,7 +114,7 @@ def test_raw_response_list(self, client: Runloop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
axon = response.parse()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(SyncAxonsCursorIDPage[AxonView], axon, path=["response"])
@parametrize
def test_streaming_response_list(self, client: Runloop) -> None:
@@ -108,7 +123,7 @@ def test_streaming_response_list(self, client: Runloop) -> None:
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
axon = response.parse()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(SyncAxonsCursorIDPage[AxonView], axon, path=["response"])
assert cast(Any, response.is_closed) is True
@@ -282,7 +297,18 @@ async def test_path_params_retrieve(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list(self, async_client: AsyncRunloop) -> None:
axon = await async_client.axons.list()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(AsyncAxonsCursorIDPage[AxonView], axon, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.list(
+ id="id",
+ include_total_count=True,
+ limit=0,
+ name="name",
+ starting_after="starting_after",
+ )
+ assert_matches_type(AsyncAxonsCursorIDPage[AxonView], axon, path=["response"])
@parametrize
async def test_raw_response_list(self, async_client: AsyncRunloop) -> None:
@@ -291,7 +317,7 @@ async def test_raw_response_list(self, async_client: AsyncRunloop) -> None:
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
axon = await response.parse()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(AsyncAxonsCursorIDPage[AxonView], axon, path=["response"])
@parametrize
async def test_streaming_response_list(self, async_client: AsyncRunloop) -> None:
@@ -300,7 +326,7 @@ async def test_streaming_response_list(self, async_client: AsyncRunloop) -> None
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
axon = await response.parse()
- assert_matches_type(AxonListView, axon, path=["response"])
+ assert_matches_type(AsyncAxonsCursorIDPage[AxonView], axon, path=["response"])
assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py
index ab78cd157..c04de1d06 100644
--- a/tests/api_resources/test_devboxes.py
+++ b/tests/api_resources/test_devboxes.py
@@ -113,6 +113,7 @@ def test_method_create_with_all_params(self, client: Runloop) -> None:
tunnel={
"auth_mode": "open",
"http_keep_alive": True,
+ "wake_on_http": True,
},
)
assert_matches_type(DevboxView, devbox, path=["response"])
@@ -404,6 +405,7 @@ def test_method_enable_tunnel_with_all_params(self, client: Runloop) -> None:
id="id",
auth_mode="open",
http_keep_alive=True,
+ wake_on_http=True,
)
assert_matches_type(TunnelView, devbox, path=["response"])
@@ -1727,6 +1729,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) -
tunnel={
"auth_mode": "open",
"http_keep_alive": True,
+ "wake_on_http": True,
},
)
assert_matches_type(DevboxView, devbox, path=["response"])
@@ -2018,6 +2021,7 @@ async def test_method_enable_tunnel_with_all_params(self, async_client: AsyncRun
id="id",
auth_mode="open",
http_keep_alive=True,
+ wake_on_http=True,
)
assert_matches_type(TunnelView, devbox, path=["response"])