diff --git a/.gitignore b/.gitignore
index 2f716b579..90668e988 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.prism.log
+.stdy.log
_dev
__pycache__
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ffb929a02..f94eeca26 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "1.12.1"
+ ".": "1.13.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index ab8cc33c0..f43fecc35 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 117
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-0568973e19e8af9fa953b2ded109ab2b69e76e90e2b74f33617dbf7092e26274.yml
-openapi_spec_hash: 10ba804ce69510d7985e05c77d0ffcf6
-config_hash: de99cfce88e2d1f02246dc6c2f43bc6c
+configured_endpoints: 122
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-32e4b2dfb75745be076697d252bd80aff21c08464750928ffe2b7dd997d0b443.yml
+openapi_spec_hash: eb0ccabfcda0fb8c56b53939b56f6d80
+config_hash: c422b761c745873bce8fa5ccf03b7b98
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7fa80f3dd..1f7dfb282 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,37 @@
# Changelog
+## 1.13.0 (2026-03-24)
+
+Full Changelog: [v1.12.1...v1.13.0](https://github.com/runloopai/api-client-python/compare/v1.12.1...v1.13.0)
+
+### Features
+
+* example for using tunnels ([#754](https://github.com/runloopai/api-client-python/issues/754)) ([97bcd70](https://github.com/runloopai/api-client-python/commit/97bcd701c6aac8077b8dea9cd4d0693d524de9b7))
+
+
+### Bug Fixes
+
+* add AxonEventView schema to OpenAPI spec for SSE subscribe endpoint ([#8274](https://github.com/runloopai/api-client-python/issues/8274)) ([618f1bb](https://github.com/runloopai/api-client-python/commit/618f1bb48ff7757e5285cddd083f49ccbbeeed3c))
+* add name to Axon ([#8277](https://github.com/runloopai/api-client-python/issues/8277)) ([7bdb527](https://github.com/runloopai/api-client-python/commit/7bdb527e9011a68f456c927f138fac22d73b3035))
+* sanitize endpoint path params ([5182d36](https://github.com/runloopai/api-client-python/commit/5182d3666b20f4fe5b245201e0b992705443d024))
+* sanitize endpoint path params ([0993026](https://github.com/runloopai/api-client-python/commit/0993026b7dd67b1f7a9a81036c7fc93ab638112d))
+* **tunnels:** allow tunnel removal ([#8257](https://github.com/runloopai/api-client-python/issues/8257)) ([6cff97e](https://github.com/runloopai/api-client-python/commit/6cff97ee43a2f2c906833e9900841e34d478d176))
+
+
+### Chores
+
+* **internal:** update gitignore ([96bd6fd](https://github.com/runloopai/api-client-python/commit/96bd6fdc7b767371b21f5753729f01020f9e78ec))
+* remove dead port configuration code, mark deprecated / ignored in the API ([#8195](https://github.com/runloopai/api-client-python/issues/8195)) ([e565324](https://github.com/runloopai/api-client-python/commit/e5653245b65f7afd6210abe1b507ae64151da9b7))
+* **tests:** bump steady to v0.19.4 ([66cb637](https://github.com/runloopai/api-client-python/commit/66cb637779eaea2cacc4b1a06ac3a33f2358b0ee))
+* **tests:** bump steady to v0.19.5 ([601c93a](https://github.com/runloopai/api-client-python/commit/601c93afffb8379770ac895b89235903c8348b00))
+* **tests:** bump steady to v0.19.6 ([95b2ffc](https://github.com/runloopai/api-client-python/commit/95b2ffc5d487f6595ec1dc73b6a34696c309f67d))
+
+
+### Refactors
+
+* **tests:** switch from prism to steady ([dd8fe60](https://github.com/runloopai/api-client-python/commit/dd8fe60922808bb0f001b49a99988004195d806f))
+* undeprecate total_count from pagination API, remove remaining_count ([#8084](https://github.com/runloopai/api-client-python/issues/8084)) ([4bd524f](https://github.com/runloopai/api-client-python/commit/4bd524fa32e6aad6efeeabd8a5bbef5e3c7ea742))
+
## 1.12.1 (2026-03-19)
Full Changelog: [v1.12.0...v1.12.1](https://github.com/runloopai/api-client-python/compare/v1.12.0...v1.12.1)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cdf385047..e1abe960c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -85,7 +85,7 @@ $ pip install ./path-to-wheel-file.whl
## Running tests
-Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests.
+Most tests require you to [set up a mock server](https://github.com/dgellow/steady) against the OpenAPI spec to run the tests.
```sh
$ ./scripts/mock
diff --git a/api.md b/api.md
index 4a2dd3da3..81abd6751 100644
--- a/api.md
+++ b/api.md
@@ -87,6 +87,29 @@ Methods:
- client.agents.retrieve(id) -> AgentView
- client.agents.list(\*\*params) -> SyncAgentsCursorIDPage[AgentView]
+# Axons
+
+Types:
+
+```python
+from runloop_api_client.types import (
+ AxonCreateParams,
+ AxonEventView,
+ AxonListView,
+ AxonView,
+ PublishParams,
+ PublishResultView,
+)
+```
+
+Methods:
+
+- client.axons.create(\*\*params) -> AxonView
+- client.axons.retrieve(id) -> AxonView
+- client.axons.list() -> AxonListView
+- client.axons.publish(id, \*\*params) -> PublishResultView
+- client.axons.subscribe_sse(id) -> AxonEventView
+
# Blueprints
Types:
@@ -155,7 +178,7 @@ Methods:
- client.devboxes.keep_alive(id) -> object
- client.devboxes.list_disk_snapshots(\*\*params) -> SyncDiskSnapshotsCursorIDPage[DevboxSnapshotView]
- client.devboxes.read_file_contents(id, \*\*params) -> str
-- client.devboxes.remove_tunnel(id, \*\*params) -> object
+- client.devboxes.remove_tunnel(id) -> object
- client.devboxes.resume(id) -> DevboxView
- client.devboxes.retrieve_resource_usage(id) -> DevboxResourceUsageView
- client.devboxes.shutdown(id, \*\*params) -> DevboxView
diff --git a/pyproject.toml b/pyproject.toml
index 1fccbf83b..931df6d19 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
-version = "1.12.1"
+version = "1.13.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
diff --git a/scripts/mock b/scripts/mock
index bcf3b392b..b319bdfbb 100755
--- a/scripts/mock
+++ b/scripts/mock
@@ -19,34 +19,34 @@ fi
echo "==> Starting mock server with URL ${URL}"
-# Run prism mock on the given spec
+# Run steady mock on the given spec
if [ "$1" == "--daemon" ]; then
# Pre-install the package so the download doesn't eat into the startup timeout
- npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version
+ npm exec --package=@stdy/cli@0.19.6 -- steady --version
- npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log &
+ npm exec --package=@stdy/cli@0.19.6 -- 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 &
- # Wait for server to come online (max 30s)
+ # Wait for server to come online via health endpoint (max 30s)
echo -n "Waiting for server"
attempts=0
- while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
+ while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do
+ if ! kill -0 $! 2>/dev/null; then
+ echo
+ cat .stdy.log
+ exit 1
+ fi
attempts=$((attempts + 1))
if [ "$attempts" -ge 300 ]; then
echo
- echo "Timed out waiting for Prism server to start"
- cat .prism.log
+ echo "Timed out waiting for Steady server to start"
+ cat .stdy.log
exit 1
fi
echo -n "."
sleep 0.1
done
- if grep -q "✖ fatal" ".prism.log"; then
- cat .prism.log
- exit 1
- fi
-
echo
else
- npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL"
+ npm exec --package=@stdy/cli@0.19.6 -- 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"
fi
diff --git a/scripts/test b/scripts/test
index df5c29f74..bc3f79742 100755
--- a/scripts/test
+++ b/scripts/test
@@ -9,8 +9,8 @@ GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
-function prism_is_running() {
- curl --silent "http://localhost:4010" >/dev/null 2>&1
+function steady_is_running() {
+ curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1
}
kill_server_on_port() {
@@ -25,7 +25,7 @@ function is_overriding_api_base_url() {
[ -n "$TEST_API_BASE_URL" ]
}
-if ! is_overriding_api_base_url && ! prism_is_running ; then
+if ! is_overriding_api_base_url && ! steady_is_running ; then
# When we exit this script, make sure to kill the background mock server process
trap 'kill_server_on_port 4010' EXIT
@@ -36,19 +36,19 @@ fi
if is_overriding_api_base_url ; then
echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}"
echo
-elif ! prism_is_running ; then
- echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server"
+elif ! steady_is_running ; then
+ echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server"
echo -e "running against your OpenAPI spec."
echo
echo -e "To run the server, pass in the path or url of your OpenAPI"
- echo -e "spec to the prism command:"
+ echo -e "spec to the steady command:"
echo
- echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}"
+ echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- 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
exit 1
else
- echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}"
+ echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}"
echo
fi
diff --git a/src/runloop_api_client/_client.py b/src/runloop_api_client/_client.py
index 0f626950b..3b5ab20db 100644
--- a/src/runloop_api_client/_client.py
+++ b/src/runloop_api_client/_client.py
@@ -32,6 +32,7 @@
if TYPE_CHECKING:
from .resources import (
+ axons,
agents,
objects,
secrets,
@@ -46,6 +47,7 @@
gateway_configs,
network_policies,
)
+ from .resources.axons import AxonsResource, AsyncAxonsResource
from .resources.agents import AgentsResource, AsyncAgentsResource
from .resources.objects import ObjectsResource, AsyncObjectsResource
from .resources.secrets import SecretsResource, AsyncSecretsResource
@@ -144,6 +146,12 @@ def agents(self) -> AgentsResource:
return AgentsResource(self)
+ @cached_property
+ def axons(self) -> AxonsResource:
+ from .resources.axons import AxonsResource
+
+ return AxonsResource(self)
+
@cached_property
def blueprints(self) -> BlueprintsResource:
from .resources.blueprints import BlueprintsResource
@@ -392,6 +400,12 @@ def agents(self) -> AsyncAgentsResource:
return AsyncAgentsResource(self)
+ @cached_property
+ def axons(self) -> AsyncAxonsResource:
+ from .resources.axons import AsyncAxonsResource
+
+ return AsyncAxonsResource(self)
+
@cached_property
def blueprints(self) -> AsyncBlueprintsResource:
from .resources.blueprints import AsyncBlueprintsResource
@@ -589,6 +603,12 @@ def agents(self) -> agents.AgentsResourceWithRawResponse:
return AgentsResourceWithRawResponse(self._client.agents)
+ @cached_property
+ def axons(self) -> axons.AxonsResourceWithRawResponse:
+ from .resources.axons import AxonsResourceWithRawResponse
+
+ return AxonsResourceWithRawResponse(self._client.axons)
+
@cached_property
def blueprints(self) -> blueprints.BlueprintsResourceWithRawResponse:
from .resources.blueprints import BlueprintsResourceWithRawResponse
@@ -674,6 +694,12 @@ def agents(self) -> agents.AsyncAgentsResourceWithRawResponse:
return AsyncAgentsResourceWithRawResponse(self._client.agents)
+ @cached_property
+ def axons(self) -> axons.AsyncAxonsResourceWithRawResponse:
+ from .resources.axons import AsyncAxonsResourceWithRawResponse
+
+ return AsyncAxonsResourceWithRawResponse(self._client.axons)
+
@cached_property
def blueprints(self) -> blueprints.AsyncBlueprintsResourceWithRawResponse:
from .resources.blueprints import AsyncBlueprintsResourceWithRawResponse
@@ -759,6 +785,12 @@ def agents(self) -> agents.AgentsResourceWithStreamingResponse:
return AgentsResourceWithStreamingResponse(self._client.agents)
+ @cached_property
+ def axons(self) -> axons.AxonsResourceWithStreamingResponse:
+ from .resources.axons import AxonsResourceWithStreamingResponse
+
+ return AxonsResourceWithStreamingResponse(self._client.axons)
+
@cached_property
def blueprints(self) -> blueprints.BlueprintsResourceWithStreamingResponse:
from .resources.blueprints import BlueprintsResourceWithStreamingResponse
@@ -844,6 +876,12 @@ def agents(self) -> agents.AsyncAgentsResourceWithStreamingResponse:
return AsyncAgentsResourceWithStreamingResponse(self._client.agents)
+ @cached_property
+ def axons(self) -> axons.AsyncAxonsResourceWithStreamingResponse:
+ from .resources.axons import AsyncAxonsResourceWithStreamingResponse
+
+ return AsyncAxonsResourceWithStreamingResponse(self._client.axons)
+
@cached_property
def blueprints(self) -> blueprints.AsyncBlueprintsResourceWithStreamingResponse:
from .resources.blueprints import AsyncBlueprintsResourceWithStreamingResponse
diff --git a/src/runloop_api_client/_utils/__init__.py b/src/runloop_api_client/_utils/__init__.py
index 80df24dba..64f8a6d9c 100644
--- a/src/runloop_api_client/_utils/__init__.py
+++ b/src/runloop_api_client/_utils/__init__.py
@@ -1,4 +1,5 @@
# isort: skip_file
+from ._path import path_template as path_template
from ._sync import asyncify as asyncify
from ._proxy import LazyProxy as LazyProxy
from ._utils import (
diff --git a/src/runloop_api_client/_utils/_path.py b/src/runloop_api_client/_utils/_path.py
new file mode 100644
index 000000000..4d6e1e4cb
--- /dev/null
+++ b/src/runloop_api_client/_utils/_path.py
@@ -0,0 +1,127 @@
+from __future__ import annotations
+
+import re
+from typing import (
+ Any,
+ Mapping,
+ Callable,
+)
+from urllib.parse import quote
+
+# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E).
+_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$")
+
+_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}")
+
+
+def _quote_path_segment_part(value: str) -> str:
+ """Percent-encode `value` for use in a URI path segment.
+
+ Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe.
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
+ """
+ # quote() already treats unreserved characters (letters, digits, and -._~)
+ # as safe, so we only need to add sub-delims, ':', and '@'.
+ # Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted.
+ return quote(value, safe="!$&'()*+,;=:@")
+
+
+def _quote_query_part(value: str) -> str:
+ """Percent-encode `value` for use in a URI query string.
+
+ Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe.
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.4
+ """
+ return quote(value, safe="!$'()*+,;:@/?")
+
+
+def _quote_fragment_part(value: str) -> str:
+ """Percent-encode `value` for use in a URI fragment.
+
+ Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe.
+ https://datatracker.ietf.org/doc/html/rfc3986#section-3.5
+ """
+ return quote(value, safe="!$&'()*+,;=:@/?")
+
+
+def _interpolate(
+ template: str,
+ values: Mapping[str, Any],
+ quoter: Callable[[str], str],
+) -> str:
+ """Replace {name} placeholders in `template`, quoting each value with `quoter`.
+
+ Placeholder names are looked up in `values`.
+
+ Raises:
+ KeyError: If a placeholder is not found in `values`.
+ """
+ # re.split with a capturing group returns alternating
+ # [text, name, text, name, ..., text] elements.
+ parts = _PLACEHOLDER_RE.split(template)
+
+ for i in range(1, len(parts), 2):
+ name = parts[i]
+ if name not in values:
+ raise KeyError(f"a value for placeholder {{{name}}} was not provided")
+ val = values[name]
+ if val is None:
+ parts[i] = "null"
+ elif isinstance(val, bool):
+ parts[i] = "true" if val else "false"
+ else:
+ parts[i] = quoter(str(values[name]))
+
+ return "".join(parts)
+
+
+def path_template(template: str, /, **kwargs: Any) -> str:
+ """Interpolate {name} placeholders in `template` from keyword arguments.
+
+ Args:
+ template: The template string containing {name} placeholders.
+ **kwargs: Keyword arguments to interpolate into the template.
+
+ Returns:
+ The template with placeholders interpolated and percent-encoded.
+
+ Safe characters for percent-encoding are dependent on the URI component.
+ Placeholders in path and fragment portions are percent-encoded where the `segment`
+ and `fragment` sets from RFC 3986 respectively are considered safe.
+ Placeholders in the query portion are percent-encoded where the `query` set from
+ RFC 3986 §3.3 is considered safe except for = and & characters.
+
+ Raises:
+ KeyError: If a placeholder is not found in `kwargs`.
+ ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments).
+ """
+ # Split the template into path, query, and fragment portions.
+ fragment_template: str | None = None
+ query_template: str | None = None
+
+ rest = template
+ if "#" in rest:
+ rest, fragment_template = rest.split("#", 1)
+ if "?" in rest:
+ rest, query_template = rest.split("?", 1)
+ path_template = rest
+
+ # Interpolate each portion with the appropriate quoting rules.
+ path_result = _interpolate(path_template, kwargs, _quote_path_segment_part)
+
+ # Reject dot-segments (. and ..) in the final assembled path. The check
+ # runs after interpolation so that adjacent placeholders or a mix of static
+ # text and placeholders that together form a dot-segment are caught.
+ # Also reject percent-encoded dot-segments to protect against incorrectly
+ # implemented normalization in servers/proxies.
+ for segment in path_result.split("/"):
+ if _DOT_SEGMENT_RE.match(segment):
+ raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed")
+
+ result = path_result
+ if query_template is not None:
+ result += "?" + _interpolate(query_template, kwargs, _quote_query_part)
+ if fragment_template is not None:
+ result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part)
+
+ return result
diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py
index f93dfde0e..5dafd5d62 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.12.1" # x-release-please-version
+__version__ = "1.13.0" # x-release-please-version
diff --git a/src/runloop_api_client/resources/__init__.py b/src/runloop_api_client/resources/__init__.py
index 2e0584f25..58d7488f6 100644
--- a/src/runloop_api_client/resources/__init__.py
+++ b/src/runloop_api_client/resources/__init__.py
@@ -1,5 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .axons import (
+ AxonsResource,
+ AsyncAxonsResource,
+ AxonsResourceWithRawResponse,
+ AsyncAxonsResourceWithRawResponse,
+ AxonsResourceWithStreamingResponse,
+ AsyncAxonsResourceWithStreamingResponse,
+)
from .agents import (
AgentsResource,
AsyncAgentsResource,
@@ -130,6 +138,12 @@
"AsyncAgentsResourceWithRawResponse",
"AgentsResourceWithStreamingResponse",
"AsyncAgentsResourceWithStreamingResponse",
+ "AxonsResource",
+ "AsyncAxonsResource",
+ "AxonsResourceWithRawResponse",
+ "AsyncAxonsResourceWithRawResponse",
+ "AxonsResourceWithStreamingResponse",
+ "AsyncAxonsResourceWithStreamingResponse",
"BlueprintsResource",
"AsyncBlueprintsResource",
"BlueprintsResourceWithRawResponse",
diff --git a/src/runloop_api_client/resources/agents.py b/src/runloop_api_client/resources/agents.py
index 9ac9f8c02..082d5725c 100644
--- a/src/runloop_api_client/resources/agents.py
+++ b/src/runloop_api_client/resources/agents.py
@@ -8,7 +8,7 @@
from ..types import agent_list_params, agent_create_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -127,7 +127,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/agents/{id}",
+ path_template("/v1/agents/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -137,6 +137,7 @@ def retrieve(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
is_public: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
@@ -154,6 +155,9 @@ def list(
List all Agents for the authenticated account with pagination support.
Args:
+ 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.
+
is_public: Filter agents by public visibility.
limit: The limit of items to return. Default is 20. Max is 5000.
@@ -184,6 +188,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"is_public": is_public,
"limit": limit,
"name": name,
@@ -300,7 +305,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/agents/{id}",
+ path_template("/v1/agents/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -310,6 +315,7 @@ async def retrieve(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
is_public: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
@@ -327,6 +333,9 @@ def list(
List all Agents for the authenticated account with pagination support.
Args:
+ 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.
+
is_public: Filter agents by public visibility.
limit: The limit of items to return. Default is 20. Max is 5000.
@@ -357,6 +366,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"is_public": is_public,
"limit": limit,
"name": name,
diff --git a/src/runloop_api_client/resources/axons.py b/src/runloop_api_client/resources/axons.py
new file mode 100644
index 000000000..9758057de
--- /dev/null
+++ b/src/runloop_api_client/resources/axons.py
@@ -0,0 +1,532 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal
+
+import httpx
+
+from ..types import 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
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from .._streaming import Stream, AsyncStream
+from .._base_client import 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
+
+__all__ = ["AxonsResource", "AsyncAxonsResource"]
+
+
+class AxonsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AxonsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runloopai/api-client-python#accessing-raw-response-data-eg-headers
+ """
+ return AxonsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AxonsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runloopai/api-client-python#with_streaming_response
+ """
+ return AxonsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ name: Optional[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,
+ idempotency_key: str | None = None,
+ ) -> AxonView:
+ """
+ [Beta] Create a new axon.
+
+ Args:
+ name: (Optional) Name for the axon.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ return self._post(
+ "/v1/axons",
+ body=maybe_transform({"name": name}, axon_create_params.AxonCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=AxonView,
+ )
+
+ def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> AxonView:
+ """
+ [Beta] Get an axon given ID.
+
+ Args:
+ 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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._get(
+ path_template("/v1/axons/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonView,
+ )
+
+ def list(
+ self,
+ *,
+ # 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(
+ "/v1/axons",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonListView,
+ )
+
+ def publish(
+ self,
+ id: str,
+ *,
+ event_type: str,
+ origin: Literal["EXTERNAL_EVENT", "AGENT_EVENT", "USER_EVENT"],
+ payload: str,
+ source: str,
+ # 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,
+ idempotency_key: str | None = None,
+ ) -> PublishResultView:
+ """
+ [Beta] Publish an event to a specified axon.
+
+ Args:
+ event_type: The event type (e.g. push, pull_request).
+
+ origin: Event origin.
+
+ payload: Event payload.
+
+ source: The source of the event (e.g. github, slack).
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._post(
+ path_template("/v1/axons/{id}/publish", id=id),
+ body=maybe_transform(
+ {
+ "event_type": event_type,
+ "origin": origin,
+ "payload": payload,
+ "source": source,
+ },
+ axon_publish_params.AxonPublishParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=PublishResultView,
+ )
+
+ def subscribe_sse(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> Stream[AxonEventView]:
+ """
+ [Beta] Subscribe to an axon event stream via server-sent events.
+
+ Args:
+ 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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return self._get(
+ path_template("/v1/axons/{id}/subscribe/sse", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonEventView,
+ stream=True,
+ stream_cls=Stream[AxonEventView],
+ )
+
+
+class AsyncAxonsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAxonsResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/runloopai/api-client-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAxonsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAxonsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/runloopai/api-client-python#with_streaming_response
+ """
+ return AsyncAxonsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ name: Optional[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,
+ idempotency_key: str | None = None,
+ ) -> AxonView:
+ """
+ [Beta] Create a new axon.
+
+ Args:
+ name: (Optional) Name for the axon.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ return await self._post(
+ "/v1/axons",
+ body=await async_maybe_transform({"name": name}, axon_create_params.AxonCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=AxonView,
+ )
+
+ async def retrieve(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> AxonView:
+ """
+ [Beta] Get an axon given ID.
+
+ Args:
+ 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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._get(
+ path_template("/v1/axons/{id}", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonView,
+ )
+
+ async def list(
+ self,
+ *,
+ # 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(
+ "/v1/axons",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonListView,
+ )
+
+ async def publish(
+ self,
+ id: str,
+ *,
+ event_type: str,
+ origin: Literal["EXTERNAL_EVENT", "AGENT_EVENT", "USER_EVENT"],
+ payload: str,
+ source: str,
+ # 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,
+ idempotency_key: str | None = None,
+ ) -> PublishResultView:
+ """
+ [Beta] Publish an event to a specified axon.
+
+ Args:
+ event_type: The event type (e.g. push, pull_request).
+
+ origin: Event origin.
+
+ payload: Event payload.
+
+ source: The source of the event (e.g. github, slack).
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._post(
+ path_template("/v1/axons/{id}/publish", id=id),
+ body=await async_maybe_transform(
+ {
+ "event_type": event_type,
+ "origin": origin,
+ "payload": payload,
+ "source": source,
+ },
+ axon_publish_params.AxonPublishParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=PublishResultView,
+ )
+
+ async def subscribe_sse(
+ self,
+ id: str,
+ *,
+ # 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,
+ ) -> AsyncStream[AxonEventView]:
+ """
+ [Beta] Subscribe to an axon event stream via server-sent events.
+
+ Args:
+ 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
+ """
+ if not id:
+ raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
+ return await self._get(
+ path_template("/v1/axons/{id}/subscribe/sse", id=id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AxonEventView,
+ stream=True,
+ stream_cls=AsyncStream[AxonEventView],
+ )
+
+
+class AxonsResourceWithRawResponse:
+ def __init__(self, axons: AxonsResource) -> None:
+ self._axons = axons
+
+ self.create = to_raw_response_wrapper(
+ axons.create,
+ )
+ self.retrieve = to_raw_response_wrapper(
+ axons.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ axons.list,
+ )
+ self.publish = to_raw_response_wrapper(
+ axons.publish,
+ )
+ self.subscribe_sse = to_raw_response_wrapper(
+ axons.subscribe_sse,
+ )
+
+
+class AsyncAxonsResourceWithRawResponse:
+ def __init__(self, axons: AsyncAxonsResource) -> None:
+ self._axons = axons
+
+ self.create = async_to_raw_response_wrapper(
+ axons.create,
+ )
+ self.retrieve = async_to_raw_response_wrapper(
+ axons.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ axons.list,
+ )
+ self.publish = async_to_raw_response_wrapper(
+ axons.publish,
+ )
+ self.subscribe_sse = async_to_raw_response_wrapper(
+ axons.subscribe_sse,
+ )
+
+
+class AxonsResourceWithStreamingResponse:
+ def __init__(self, axons: AxonsResource) -> None:
+ self._axons = axons
+
+ self.create = to_streamed_response_wrapper(
+ axons.create,
+ )
+ self.retrieve = to_streamed_response_wrapper(
+ axons.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ axons.list,
+ )
+ self.publish = to_streamed_response_wrapper(
+ axons.publish,
+ )
+ self.subscribe_sse = to_streamed_response_wrapper(
+ axons.subscribe_sse,
+ )
+
+
+class AsyncAxonsResourceWithStreamingResponse:
+ def __init__(self, axons: AsyncAxonsResource) -> None:
+ self._axons = axons
+
+ self.create = async_to_streamed_response_wrapper(
+ axons.create,
+ )
+ self.retrieve = async_to_streamed_response_wrapper(
+ axons.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ axons.list,
+ )
+ self.publish = async_to_streamed_response_wrapper(
+ axons.publish,
+ )
+ self.subscribe_sse = async_to_streamed_response_wrapper(
+ axons.subscribe_sse,
+ )
diff --git a/src/runloop_api_client/resources/benchmark_jobs.py b/src/runloop_api_client/resources/benchmark_jobs.py
index f6172d118..e57e58c33 100644
--- a/src/runloop_api_client/resources/benchmark_jobs.py
+++ b/src/runloop_api_client/resources/benchmark_jobs.py
@@ -8,7 +8,7 @@
from ..types import benchmark_job_list_params, benchmark_job_create_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -121,7 +121,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/benchmark_jobs/{id}",
+ path_template("/v1/benchmark_jobs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -131,6 +131,7 @@ def retrieve(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -145,6 +146,9 @@ def list(
[Beta] List all BenchmarkJobs matching filter.
Args:
+ 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 name
@@ -168,6 +172,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -276,7 +281,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/benchmark_jobs/{id}",
+ path_template("/v1/benchmark_jobs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -286,6 +291,7 @@ async def retrieve(
async def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -300,6 +306,9 @@ async def list(
[Beta] List all BenchmarkJobs matching filter.
Args:
+ 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 name
@@ -323,6 +332,7 @@ async def list(
timeout=timeout,
query=await async_maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
diff --git a/src/runloop_api_client/resources/benchmark_runs.py b/src/runloop_api_client/resources/benchmark_runs.py
index 964497cde..27e327d3d 100644
--- a/src/runloop_api_client/resources/benchmark_runs.py
+++ b/src/runloop_api_client/resources/benchmark_runs.py
@@ -8,7 +8,7 @@
from ..types import benchmark_run_list_params, benchmark_run_list_scenario_runs_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform
+from .._utils import path_template, maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -71,7 +71,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/benchmark_runs/{id}",
+ path_template("/v1/benchmark_runs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -82,6 +82,7 @@ def list(
self,
*,
benchmark_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -98,6 +99,9 @@ def list(
Args:
benchmark_id: The Benchmark ID to filter by.
+ 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 name
@@ -123,6 +127,7 @@ def list(
query=maybe_transform(
{
"benchmark_id": benchmark_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -165,7 +170,7 @@ def cancel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/benchmark_runs/{id}/cancel",
+ path_template("/v1/benchmark_runs/{id}/cancel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -205,7 +210,7 @@ def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/benchmark_runs/{id}/complete",
+ path_template("/v1/benchmark_runs/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -220,6 +225,7 @@ def list_scenario_runs(
self,
id: str,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
starting_after: str | Omit = omit,
state: Literal["running", "scoring", "scored", "completed", "canceled", "timeout", "failed"] | Omit = omit,
@@ -234,6 +240,9 @@ def list_scenario_runs(
List started scenario runs for a benchmark run.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -251,7 +260,7 @@ def list_scenario_runs(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get_api_list(
- f"/v1/benchmark_runs/{id}/scenario_runs",
+ path_template("/v1/benchmark_runs/{id}/scenario_runs", id=id),
page=SyncBenchmarkRunsCursorIDPage[ScenarioRunView],
options=make_request_options(
extra_headers=extra_headers,
@@ -260,6 +269,7 @@ def list_scenario_runs(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
"state": state,
@@ -317,7 +327,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/benchmark_runs/{id}",
+ path_template("/v1/benchmark_runs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -328,6 +338,7 @@ def list(
self,
*,
benchmark_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -344,6 +355,9 @@ def list(
Args:
benchmark_id: The Benchmark ID to filter by.
+ 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 name
@@ -369,6 +383,7 @@ def list(
query=maybe_transform(
{
"benchmark_id": benchmark_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -411,7 +426,7 @@ async def cancel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/benchmark_runs/{id}/cancel",
+ path_template("/v1/benchmark_runs/{id}/cancel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -451,7 +466,7 @@ async def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/benchmark_runs/{id}/complete",
+ path_template("/v1/benchmark_runs/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -466,6 +481,7 @@ def list_scenario_runs(
self,
id: str,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
starting_after: str | Omit = omit,
state: Literal["running", "scoring", "scored", "completed", "canceled", "timeout", "failed"] | Omit = omit,
@@ -480,6 +496,9 @@ def list_scenario_runs(
List started scenario runs for a benchmark run.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -497,7 +516,7 @@ def list_scenario_runs(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get_api_list(
- f"/v1/benchmark_runs/{id}/scenario_runs",
+ path_template("/v1/benchmark_runs/{id}/scenario_runs", id=id),
page=AsyncBenchmarkRunsCursorIDPage[ScenarioRunView],
options=make_request_options(
extra_headers=extra_headers,
@@ -506,6 +525,7 @@ def list_scenario_runs(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
"state": state,
diff --git a/src/runloop_api_client/resources/benchmarks.py b/src/runloop_api_client/resources/benchmarks.py
index d23992bd2..ca5442f52 100644
--- a/src/runloop_api_client/resources/benchmarks.py
+++ b/src/runloop_api_client/resources/benchmarks.py
@@ -16,7 +16,7 @@
benchmark_update_scenarios_params,
)
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -154,7 +154,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/benchmarks/{id}",
+ path_template("/v1/benchmarks/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -218,7 +218,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/benchmarks/{id}",
+ path_template("/v1/benchmarks/{id}", id=id),
body=maybe_transform(
{
"attribution": attribution,
@@ -244,6 +244,7 @@ def update(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -258,6 +259,9 @@ def list(
List all Benchmarks matching filter.
Args:
+ 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 name
@@ -282,6 +286,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -324,7 +329,7 @@ def definitions(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/benchmarks/{id}/definitions",
+ path_template("/v1/benchmarks/{id}/definitions", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -344,6 +349,7 @@ def definitions(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | 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.
@@ -357,6 +363,9 @@ def list_public(
List all public benchmarks matching filter.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -379,6 +388,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
},
@@ -481,7 +491,7 @@ def update_scenarios(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/benchmarks/{id}/scenarios",
+ path_template("/v1/benchmarks/{id}/scenarios", id=id),
body=maybe_transform(
{
"scenarios_to_add": scenarios_to_add,
@@ -619,7 +629,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/benchmarks/{id}",
+ path_template("/v1/benchmarks/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -683,7 +693,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/benchmarks/{id}",
+ path_template("/v1/benchmarks/{id}", id=id),
body=await async_maybe_transform(
{
"attribution": attribution,
@@ -709,6 +719,7 @@ async def update(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -723,6 +734,9 @@ def list(
List all Benchmarks matching filter.
Args:
+ 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 name
@@ -747,6 +761,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -789,7 +804,7 @@ async def definitions(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/benchmarks/{id}/definitions",
+ path_template("/v1/benchmarks/{id}/definitions", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -809,6 +824,7 @@ async def definitions(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | 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.
@@ -822,6 +838,9 @@ def list_public(
List all public benchmarks matching filter.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -844,6 +863,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
},
@@ -946,7 +966,7 @@ async def update_scenarios(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/benchmarks/{id}/scenarios",
+ path_template("/v1/benchmarks/{id}/scenarios", id=id),
body=await async_maybe_transform(
{
"scenarios_to_add": scenarios_to_add,
diff --git a/src/runloop_api_client/resources/blueprints.py b/src/runloop_api_client/resources/blueprints.py
index 39eae98aa..7e5b09939 100644
--- a/src/runloop_api_client/resources/blueprints.py
+++ b/src/runloop_api_client/resources/blueprints.py
@@ -14,7 +14,7 @@
blueprint_create_from_inspection_params,
)
from .._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from .._utils import is_given, maybe_transform, async_maybe_transform
+from .._utils import is_given, path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -268,7 +268,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/blueprints/{id}",
+ path_template("/v1/blueprints/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -396,6 +396,7 @@ def create_and_await_build_complete(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -411,6 +412,9 @@ def list(
List all Blueprints or filter by name.
Args:
+ 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 name
@@ -437,6 +441,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -480,7 +485,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/blueprints/{id}/delete",
+ path_template("/v1/blueprints/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -574,6 +579,7 @@ def create_from_inspection(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -589,6 +595,9 @@ def list_public(
List all public Blueprints that are available to all users.
Args:
+ 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 name
@@ -615,6 +624,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -652,7 +662,7 @@ def logs(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/blueprints/{id}/logs",
+ path_template("/v1/blueprints/{id}/logs", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -938,7 +948,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/blueprints/{id}",
+ path_template("/v1/blueprints/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -1066,6 +1076,7 @@ async def create_and_await_build_complete(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -1081,6 +1092,9 @@ def list(
List all Blueprints or filter by name.
Args:
+ 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 name
@@ -1107,6 +1121,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -1150,7 +1165,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/blueprints/{id}/delete",
+ path_template("/v1/blueprints/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1244,6 +1259,7 @@ async def create_from_inspection(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -1259,6 +1275,9 @@ def list_public(
List all public Blueprints that are available to all users.
Args:
+ 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 name
@@ -1285,6 +1304,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -1322,7 +1342,7 @@ async def logs(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/blueprints/{id}/logs",
+ path_template("/v1/blueprints/{id}/logs", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/runloop_api_client/resources/devboxes/browsers.py b/src/runloop_api_client/resources/devboxes/browsers.py
index 517857f56..d2977464b 100644
--- a/src/runloop_api_client/resources/devboxes/browsers.py
+++ b/src/runloop_api_client/resources/devboxes/browsers.py
@@ -7,7 +7,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -113,7 +113,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/browsers/{id}",
+ path_template("/v1/devboxes/browsers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -211,7 +211,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/browsers/{id}",
+ path_template("/v1/devboxes/browsers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/runloop_api_client/resources/devboxes/computers.py b/src/runloop_api_client/resources/devboxes/computers.py
index be051db2e..4eddfccc8 100644
--- a/src/runloop_api_client/resources/devboxes/computers.py
+++ b/src/runloop_api_client/resources/devboxes/computers.py
@@ -8,7 +8,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -133,7 +133,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/computers/{id}",
+ path_template("/v1/devboxes/computers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -176,7 +176,7 @@ def keyboard_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/computers/{id}/keyboard_interaction",
+ path_template("/v1/devboxes/computers/{id}/keyboard_interaction", id=id),
body=maybe_transform(
{
"action": action,
@@ -232,7 +232,7 @@ def mouse_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/computers/{id}/mouse_interaction",
+ path_template("/v1/devboxes/computers/{id}/mouse_interaction", id=id),
body=maybe_transform(
{
"action": action,
@@ -283,7 +283,7 @@ def screen_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/computers/{id}/screen_interaction",
+ path_template("/v1/devboxes/computers/{id}/screen_interaction", id=id),
body=maybe_transform(
{"action": action}, computer_screen_interaction_params.ComputerScreenInteractionParams
),
@@ -399,7 +399,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/computers/{id}",
+ path_template("/v1/devboxes/computers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -442,7 +442,7 @@ async def keyboard_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/computers/{id}/keyboard_interaction",
+ path_template("/v1/devboxes/computers/{id}/keyboard_interaction", id=id),
body=await async_maybe_transform(
{
"action": action,
@@ -498,7 +498,7 @@ async def mouse_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/computers/{id}/mouse_interaction",
+ path_template("/v1/devboxes/computers/{id}/mouse_interaction", id=id),
body=await async_maybe_transform(
{
"action": action,
@@ -549,7 +549,7 @@ async def screen_interaction(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/computers/{id}/screen_interaction",
+ path_template("/v1/devboxes/computers/{id}/screen_interaction", id=id),
body=await async_maybe_transform(
{"action": action}, computer_screen_interaction_params.ComputerScreenInteractionParams
),
diff --git a/src/runloop_api_client/resources/devboxes/devboxes.py b/src/runloop_api_client/resources/devboxes/devboxes.py
index 406af8626..1f016f2eb 100644
--- a/src/runloop_api_client/resources/devboxes/devboxes.py
+++ b/src/runloop_api_client/resources/devboxes/devboxes.py
@@ -30,7 +30,6 @@
devbox_download_file_params,
devbox_enable_tunnel_params,
devbox_execute_async_params,
- devbox_remove_tunnel_params,
devbox_snapshot_disk_params,
devbox_wait_for_command_params,
devbox_read_file_contents_params,
@@ -39,7 +38,7 @@
devbox_write_file_contents_params,
)
from ..._types import Body, Omit, Query, Headers, NotGiven, FileTypes, omit, not_given
-from ..._utils import is_given, extract_files, maybe_transform, deepcopy_minimal, async_maybe_transform
+from ..._utils import is_given, extract_files, path_template, maybe_transform, deepcopy_minimal, async_maybe_transform
from .browsers import (
BrowsersResource,
AsyncBrowsersResource,
@@ -335,7 +334,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/{id}",
+ path_template("/v1/devboxes/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -378,7 +377,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}",
+ path_template("/v1/devboxes/{id}", id=id),
body=maybe_transform(
{
"metadata": metadata,
@@ -571,6 +570,7 @@ def create_and_await_running(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
starting_after: str | Omit = omit,
status: Literal[
@@ -588,6 +588,9 @@ def list(
List all Devboxes while optionally filtering by status.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -612,6 +615,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
"status": status,
@@ -651,7 +655,7 @@ def create_ssh_key(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/create_ssh_key",
+ path_template("/v1/devboxes/{id}/create_ssh_key", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -691,7 +695,7 @@ def delete_disk_snapshot(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/disk_snapshots/{id}/delete",
+ path_template("/v1/devboxes/disk_snapshots/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -739,7 +743,7 @@ def download_file(
timeout = 600
extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})}
return self._post(
- f"/v1/devboxes/{id}/download_file",
+ path_template("/v1/devboxes/{id}/download_file", id=id),
body=maybe_transform({"path": path}, devbox_download_file_params.DevboxDownloadFileParams),
options=make_request_options(
extra_headers=extra_headers,
@@ -792,7 +796,7 @@ def enable_tunnel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/enable_tunnel",
+ path_template("/v1/devboxes/{id}/enable_tunnel", id=id),
body=maybe_transform(
{
"auth_mode": auth_mode,
@@ -869,7 +873,7 @@ def execute(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return self._post(
- f"/v1/devboxes/{id}/execute",
+ path_template("/v1/devboxes/{id}/execute", id=id),
body=maybe_transform(
{
"command": command,
@@ -997,7 +1001,7 @@ def execute_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/execute_async",
+ path_template("/v1/devboxes/{id}/execute_async", id=id),
body=maybe_transform(
{
"command": command,
@@ -1069,7 +1073,7 @@ def execute_sync(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return self._post(
- f"/v1/devboxes/{id}/execute_sync",
+ path_template("/v1/devboxes/{id}/execute_sync", id=id),
body=maybe_transform(
{
"command": command,
@@ -1118,7 +1122,7 @@ def keep_alive(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/keep_alive",
+ path_template("/v1/devboxes/{id}/keep_alive", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1133,6 +1137,7 @@ def list_disk_snapshots(
self,
*,
devbox_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
metadata_key: str | Omit = omit,
metadata_key_in: str | Omit = omit,
@@ -1152,6 +1157,9 @@ def list_disk_snapshots(
Args:
devbox_id: Devbox ID to filter by.
+ 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.
metadata_key: Filter snapshots by metadata key-value pair. Can be used multiple times for
@@ -1182,6 +1190,7 @@ def list_disk_snapshots(
query=maybe_transform(
{
"devbox_id": devbox_id,
+ "include_total_count": include_total_count,
"limit": limit,
"metadata_key": metadata_key,
"metadata_key_in": metadata_key_in,
@@ -1233,7 +1242,7 @@ def read_file_contents(
timeout = 600
extra_headers = {"Accept": "text/plain", **(extra_headers or {})}
return self._post(
- f"/v1/devboxes/{id}/read_file_contents",
+ path_template("/v1/devboxes/{id}/read_file_contents", id=id),
body=maybe_transform(
{"file_path": file_path}, devbox_read_file_contents_params.DevboxReadFileContentsParams
),
@@ -1247,14 +1256,10 @@ def read_file_contents(
cast_to=str,
)
- @typing_extensions.deprecated(
- "remove_tunnel is deprecated; V2 tunnels cannot be removed and close on devbox shutdown."
- )
def remove_tunnel(
self,
id: str,
*,
- port: int,
# 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,
@@ -1263,14 +1268,10 @@ def remove_tunnel(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
idempotency_key: str | None = None,
) -> object:
- """[Deprecated] V2 tunnels cannot be removed and close on devbox shutdown.
-
- This endpoint
- removes a legacy tunnel.
+ """
+ Remove an existing V2 tunnel from the Devbox.
Args:
- port: Devbox port that tunnel will expose.
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -1284,8 +1285,7 @@ def remove_tunnel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/remove_tunnel",
- body=maybe_transform({"port": port}, devbox_remove_tunnel_params.DevboxRemoveTunnelParams),
+ path_template("/v1/devboxes/{id}/remove_tunnel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1328,7 +1328,7 @@ def resume(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/resume",
+ path_template("/v1/devboxes/{id}/resume", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1369,7 +1369,7 @@ def retrieve_resource_usage(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/{id}/usage",
+ path_template("/v1/devboxes/{id}/usage", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -1413,7 +1413,7 @@ def shutdown(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/shutdown",
+ path_template("/v1/devboxes/{id}/shutdown", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1466,7 +1466,7 @@ def snapshot_disk(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return self._post(
- f"/v1/devboxes/{id}/snapshot_disk",
+ path_template("/v1/devboxes/{id}/snapshot_disk", id=id),
body=maybe_transform(
{
"commit_message": commit_message,
@@ -1525,7 +1525,7 @@ def snapshot_disk_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/snapshot_disk_async",
+ path_template("/v1/devboxes/{id}/snapshot_disk_async", id=id),
body=maybe_transform(
{
"commit_message": commit_message,
@@ -1575,7 +1575,7 @@ def suspend(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/suspend",
+ path_template("/v1/devboxes/{id}/suspend", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -1636,7 +1636,7 @@ def upload_file(
# multipart/form-data; boundary=---abc--
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return self._post(
- f"/v1/devboxes/{id}/upload_file",
+ path_template("/v1/devboxes/{id}/upload_file", id=id),
body=maybe_transform(body, devbox_upload_file_params.DevboxUploadFileParams),
files=files,
options=make_request_options(
@@ -1694,7 +1694,11 @@ def wait_for_command(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=maybe_transform(
{
"statuses": statuses,
@@ -1753,7 +1757,7 @@ def write_file_contents(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return self._post(
- f"/v1/devboxes/{id}/write_file_contents",
+ path_template("/v1/devboxes/{id}/write_file_contents", id=id),
body=maybe_transform(
{
"contents": contents,
@@ -1969,7 +1973,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/{id}",
+ path_template("/v1/devboxes/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -2181,7 +2185,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}",
+ path_template("/v1/devboxes/{id}", id=id),
body=await async_maybe_transform(
{
"metadata": metadata,
@@ -2202,6 +2206,7 @@ async def update(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
starting_after: str | Omit = omit,
status: Literal[
@@ -2219,6 +2224,9 @@ def list(
List all Devboxes while optionally filtering by status.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -2243,6 +2251,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
"status": status,
@@ -2282,7 +2291,7 @@ async def create_ssh_key(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/create_ssh_key",
+ path_template("/v1/devboxes/{id}/create_ssh_key", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -2322,7 +2331,7 @@ async def delete_disk_snapshot(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/disk_snapshots/{id}/delete",
+ path_template("/v1/devboxes/disk_snapshots/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -2370,7 +2379,7 @@ async def download_file(
timeout = 600
extra_headers = {"Accept": "application/octet-stream", **(extra_headers or {})}
return await self._post(
- f"/v1/devboxes/{id}/download_file",
+ path_template("/v1/devboxes/{id}/download_file", id=id),
body=await async_maybe_transform({"path": path}, devbox_download_file_params.DevboxDownloadFileParams),
options=make_request_options(
extra_headers=extra_headers,
@@ -2423,7 +2432,7 @@ async def enable_tunnel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/enable_tunnel",
+ path_template("/v1/devboxes/{id}/enable_tunnel", id=id),
body=await async_maybe_transform(
{
"auth_mode": auth_mode,
@@ -2500,7 +2509,7 @@ async def execute(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return await self._post(
- f"/v1/devboxes/{id}/execute",
+ path_template("/v1/devboxes/{id}/execute", id=id),
body=await async_maybe_transform(
{
"command": command,
@@ -2627,7 +2636,7 @@ async def execute_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/execute_async",
+ path_template("/v1/devboxes/{id}/execute_async", id=id),
body=await async_maybe_transform(
{
"command": command,
@@ -2699,7 +2708,7 @@ async def execute_sync(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return await self._post(
- f"/v1/devboxes/{id}/execute_sync",
+ path_template("/v1/devboxes/{id}/execute_sync", id=id),
body=await async_maybe_transform(
{
"command": command,
@@ -2748,7 +2757,7 @@ async def keep_alive(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/keep_alive",
+ path_template("/v1/devboxes/{id}/keep_alive", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -2763,6 +2772,7 @@ def list_disk_snapshots(
self,
*,
devbox_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
metadata_key: str | Omit = omit,
metadata_key_in: str | Omit = omit,
@@ -2782,6 +2792,9 @@ def list_disk_snapshots(
Args:
devbox_id: Devbox ID to filter by.
+ 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.
metadata_key: Filter snapshots by metadata key-value pair. Can be used multiple times for
@@ -2812,6 +2825,7 @@ def list_disk_snapshots(
query=maybe_transform(
{
"devbox_id": devbox_id,
+ "include_total_count": include_total_count,
"limit": limit,
"metadata_key": metadata_key,
"metadata_key_in": metadata_key_in,
@@ -2863,7 +2877,7 @@ async def read_file_contents(
timeout = 600
extra_headers = {"Accept": "text/plain", **(extra_headers or {})}
return await self._post(
- f"/v1/devboxes/{id}/read_file_contents",
+ path_template("/v1/devboxes/{id}/read_file_contents", id=id),
body=await async_maybe_transform(
{"file_path": file_path}, devbox_read_file_contents_params.DevboxReadFileContentsParams
),
@@ -2877,14 +2891,10 @@ async def read_file_contents(
cast_to=str,
)
- @typing_extensions.deprecated(
- "remove_tunnel is deprecated; V2 tunnels cannot be removed and close on devbox shutdown."
- )
async def remove_tunnel(
self,
id: str,
*,
- port: int,
# 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,
@@ -2893,14 +2903,10 @@ async def remove_tunnel(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
idempotency_key: str | None = None,
) -> object:
- """[Deprecated] V2 tunnels cannot be removed and close on devbox shutdown.
-
- This endpoint
- removes a legacy tunnel.
+ """
+ Remove an existing V2 tunnel from the Devbox.
Args:
- port: Devbox port that tunnel will expose.
-
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -2914,8 +2920,7 @@ async def remove_tunnel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/remove_tunnel",
- body=await async_maybe_transform({"port": port}, devbox_remove_tunnel_params.DevboxRemoveTunnelParams),
+ path_template("/v1/devboxes/{id}/remove_tunnel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -2958,7 +2963,7 @@ async def resume(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/resume",
+ path_template("/v1/devboxes/{id}/resume", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -2999,7 +3004,7 @@ async def retrieve_resource_usage(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/{id}/usage",
+ path_template("/v1/devboxes/{id}/usage", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -3043,7 +3048,7 @@ async def shutdown(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/shutdown",
+ path_template("/v1/devboxes/{id}/shutdown", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -3096,7 +3101,7 @@ async def snapshot_disk(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return await self._post(
- f"/v1/devboxes/{id}/snapshot_disk",
+ path_template("/v1/devboxes/{id}/snapshot_disk", id=id),
body=await async_maybe_transform(
{
"commit_message": commit_message,
@@ -3155,7 +3160,7 @@ async def snapshot_disk_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/snapshot_disk_async",
+ path_template("/v1/devboxes/{id}/snapshot_disk_async", id=id),
body=await async_maybe_transform(
{
"commit_message": commit_message,
@@ -3205,7 +3210,7 @@ async def suspend(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/suspend",
+ path_template("/v1/devboxes/{id}/suspend", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -3266,7 +3271,7 @@ async def upload_file(
# multipart/form-data; boundary=---abc--
extra_headers = {"Content-Type": "multipart/form-data", **(extra_headers or {})}
return await self._post(
- f"/v1/devboxes/{id}/upload_file",
+ path_template("/v1/devboxes/{id}/upload_file", id=id),
body=await async_maybe_transform(body, devbox_upload_file_params.DevboxUploadFileParams),
files=files,
options=make_request_options(
@@ -3324,7 +3329,11 @@ async def wait_for_command(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=await async_maybe_transform(
{
"statuses": statuses,
@@ -3385,7 +3394,7 @@ async def write_file_contents(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return await self._post(
- f"/v1/devboxes/{id}/write_file_contents",
+ path_template("/v1/devboxes/{id}/write_file_contents", id=id),
body=await async_maybe_transform(
{
"contents": contents,
@@ -3453,10 +3462,8 @@ def __init__(self, devboxes: DevboxesResource) -> None:
self.read_file_contents = to_raw_response_wrapper(
devboxes.read_file_contents,
)
- self.remove_tunnel = ( # pyright: ignore[reportDeprecated]
- to_raw_response_wrapper(
- devboxes.remove_tunnel, # pyright: ignore[reportDeprecated],
- )
+ self.remove_tunnel = to_raw_response_wrapper(
+ devboxes.remove_tunnel,
)
self.resume = to_raw_response_wrapper(
devboxes.resume,
@@ -3556,10 +3563,8 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None:
self.read_file_contents = async_to_raw_response_wrapper(
devboxes.read_file_contents,
)
- self.remove_tunnel = ( # pyright: ignore[reportDeprecated]
- async_to_raw_response_wrapper(
- devboxes.remove_tunnel, # pyright: ignore[reportDeprecated],
- )
+ self.remove_tunnel = async_to_raw_response_wrapper(
+ devboxes.remove_tunnel,
)
self.resume = async_to_raw_response_wrapper(
devboxes.resume,
@@ -3659,10 +3664,8 @@ def __init__(self, devboxes: DevboxesResource) -> None:
self.read_file_contents = to_streamed_response_wrapper(
devboxes.read_file_contents,
)
- self.remove_tunnel = ( # pyright: ignore[reportDeprecated]
- to_streamed_response_wrapper(
- devboxes.remove_tunnel, # pyright: ignore[reportDeprecated],
- )
+ self.remove_tunnel = to_streamed_response_wrapper(
+ devboxes.remove_tunnel,
)
self.resume = to_streamed_response_wrapper(
devboxes.resume,
@@ -3762,10 +3765,8 @@ def __init__(self, devboxes: AsyncDevboxesResource) -> None:
self.read_file_contents = async_to_streamed_response_wrapper(
devboxes.read_file_contents,
)
- self.remove_tunnel = ( # pyright: ignore[reportDeprecated]
- async_to_streamed_response_wrapper(
- devboxes.remove_tunnel, # pyright: ignore[reportDeprecated],
- )
+ self.remove_tunnel = async_to_streamed_response_wrapper(
+ devboxes.remove_tunnel,
)
self.resume = async_to_streamed_response_wrapper(
devboxes.resume,
diff --git a/src/runloop_api_client/resources/devboxes/disk_snapshots.py b/src/runloop_api_client/resources/devboxes/disk_snapshots.py
index b896adbb6..c4f723359 100644
--- a/src/runloop_api_client/resources/devboxes/disk_snapshots.py
+++ b/src/runloop_api_client/resources/devboxes/disk_snapshots.py
@@ -7,7 +7,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -88,7 +88,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/disk_snapshots/{id}",
+ path_template("/v1/devboxes/disk_snapshots/{id}", id=id),
body=maybe_transform(
{
"commit_message": commit_message,
@@ -111,6 +111,7 @@ def list(
self,
*,
devbox_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
metadata_key: str | Omit = omit,
metadata_key_in: str | Omit = omit,
@@ -130,6 +131,9 @@ def list(
Args:
devbox_id: Devbox ID to filter by.
+ 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.
metadata_key: Filter snapshots by metadata key-value pair. Can be used multiple times for
@@ -160,6 +164,7 @@ def list(
query=maybe_transform(
{
"devbox_id": devbox_id,
+ "include_total_count": include_total_count,
"limit": limit,
"metadata_key": metadata_key,
"metadata_key_in": metadata_key_in,
@@ -201,7 +206,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/disk_snapshots/{id}/delete",
+ path_template("/v1/devboxes/disk_snapshots/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -239,7 +244,7 @@ def query_status(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/disk_snapshots/{id}/status",
+ path_template("/v1/devboxes/disk_snapshots/{id}/status", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -339,7 +344,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/disk_snapshots/{id}",
+ path_template("/v1/devboxes/disk_snapshots/{id}", id=id),
body=await async_maybe_transform(
{
"commit_message": commit_message,
@@ -362,6 +367,7 @@ def list(
self,
*,
devbox_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
metadata_key: str | Omit = omit,
metadata_key_in: str | Omit = omit,
@@ -381,6 +387,9 @@ def list(
Args:
devbox_id: Devbox ID to filter by.
+ 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.
metadata_key: Filter snapshots by metadata key-value pair. Can be used multiple times for
@@ -411,6 +420,7 @@ def list(
query=maybe_transform(
{
"devbox_id": devbox_id,
+ "include_total_count": include_total_count,
"limit": limit,
"metadata_key": metadata_key,
"metadata_key_in": metadata_key_in,
@@ -452,7 +462,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/disk_snapshots/{id}/delete",
+ path_template("/v1/devboxes/disk_snapshots/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -490,7 +500,7 @@ async def query_status(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/disk_snapshots/{id}/status",
+ path_template("/v1/devboxes/disk_snapshots/{id}/status", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/runloop_api_client/resources/devboxes/executions.py b/src/runloop_api_client/resources/devboxes/executions.py
index 8304c038d..ff7638798 100755
--- a/src/runloop_api_client/resources/devboxes/executions.py
+++ b/src/runloop_api_client/resources/devboxes/executions.py
@@ -9,7 +9,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import is_given, maybe_transform, async_maybe_transform
+from ..._utils import is_given, path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -104,7 +104,9 @@ def retrieve(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}", devbox_id=devbox_id, execution_id=execution_id
+ ),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -210,7 +212,7 @@ def execute_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/devboxes/{id}/execute_async",
+ path_template("/v1/devboxes/{id}/execute_async", id=id),
body=maybe_transform(
{
"command": command,
@@ -278,7 +280,7 @@ def execute_sync(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return self._post(
- f"/v1/devboxes/{id}/execute_sync",
+ path_template("/v1/devboxes/{id}/execute_sync", id=id),
body=maybe_transform(
{
"command": command,
@@ -334,7 +336,11 @@ def kill(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=maybe_transform({"kill_process_group": kill_process_group}, execution_kill_params.ExecutionKillParams),
options=make_request_options(
extra_headers=extra_headers,
@@ -384,7 +390,11 @@ def send_std_in(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=maybe_transform(
{
"signal": signal,
@@ -435,12 +445,18 @@ def stream_stderr_updates(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ stream_path = path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ )
+
default_headers: Headers = {"Accept": "text/event-stream"}
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -458,7 +474,7 @@ def stream_stderr_updates(
def create_stream(last_offset: str | None) -> Stream[ExecutionUpdateChunk]:
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -520,12 +536,18 @@ def stream_stdout_updates(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ stream_path = path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ )
+
default_headers: Headers = {"Accept": "text/event-stream"}
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -543,7 +565,7 @@ def stream_stdout_updates(
def create_stream(last_offset: str | None) -> Stream[ExecutionUpdateChunk]:
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -626,7 +648,9 @@ async def retrieve(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}", devbox_id=devbox_id, execution_id=execution_id
+ ),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -730,7 +754,7 @@ async def execute_async(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/devboxes/{id}/execute_async",
+ path_template("/v1/devboxes/{id}/execute_async", id=id),
body=await async_maybe_transform(
{
"command": command,
@@ -798,7 +822,7 @@ async def execute_sync(
if not is_given(timeout) and self._client.timeout == DEFAULT_TIMEOUT:
timeout = 600
return await self._post(
- f"/v1/devboxes/{id}/execute_sync",
+ path_template("/v1/devboxes/{id}/execute_sync", id=id),
body=await async_maybe_transform(
{
"command": command,
@@ -854,7 +878,11 @@ async def kill(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/kill",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=await async_maybe_transform(
{"kill_process_group": kill_process_group}, execution_kill_params.ExecutionKillParams
),
@@ -906,7 +934,11 @@ async def send_std_in(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
return await self._post(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
+ path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/send_std_in",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ ),
body=await async_maybe_transform(
{
"signal": signal,
@@ -957,12 +989,18 @@ async def stream_stderr_updates(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ stream_path = path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ )
+
default_headers: Headers = {"Accept": "text/event-stream"}
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -980,7 +1018,7 @@ async def stream_stderr_updates(
async def create_stream(last_offset: str | None) -> AsyncStream[ExecutionUpdateChunk]:
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -1042,13 +1080,19 @@ async def stream_stdout_updates(
if not execution_id:
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
+ stream_path = path_template(
+ "/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ devbox_id=devbox_id,
+ execution_id=execution_id,
+ )
+
default_headers: Headers = {"Accept": "text/event-stream"}
merged_headers = default_headers if extra_headers is None else {**default_headers, **extra_headers}
# If caller requested a raw or streaming response wrapper, return the underlying stream as-is
if merged_headers and merged_headers.get(RAW_RESPONSE_HEADER):
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
@@ -1066,7 +1110,7 @@ async def stream_stdout_updates(
async def create_stream(last_offset: str | None) -> AsyncStream[ExecutionUpdateChunk]:
new_offset = last_offset if last_offset is not None else (None if isinstance(offset, NotGiven) else offset)
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ stream_path,
options=make_request_options(
extra_headers=merged_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/devboxes/logs.py b/src/runloop_api_client/resources/devboxes/logs.py
index 19d2c06e1..1e7383914 100644
--- a/src/runloop_api_client/resources/devboxes/logs.py
+++ b/src/runloop_api_client/resources/devboxes/logs.py
@@ -5,7 +5,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -73,7 +73,7 @@ def list(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/devboxes/{id}/logs",
+ path_template("/v1/devboxes/{id}/logs", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -143,7 +143,7 @@ async def list(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/devboxes/{id}/logs",
+ path_template("/v1/devboxes/{id}/logs", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/gateway_configs.py b/src/runloop_api_client/resources/gateway_configs.py
index 86ec22ce6..7874f7a79 100644
--- a/src/runloop_api_client/resources/gateway_configs.py
+++ b/src/runloop_api_client/resources/gateway_configs.py
@@ -8,7 +8,7 @@
from ..types import gateway_config_list_params, gateway_config_create_params, gateway_config_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -132,7 +132,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/gateway-configs/{id}",
+ path_template("/v1/gateway-configs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -181,7 +181,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/gateway-configs/{id}",
+ path_template("/v1/gateway-configs/{id}", id=id),
body=maybe_transform(
{
"auth_mechanism": auth_mechanism,
@@ -205,6 +205,7 @@ 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,
@@ -222,6 +223,9 @@ def list(
Args:
id: Filter by 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 name (partial match supported).
@@ -247,6 +251,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -287,7 +292,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/gateway-configs/{id}/delete",
+ path_template("/v1/gateway-configs/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -407,7 +412,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/gateway-configs/{id}",
+ path_template("/v1/gateway-configs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -456,7 +461,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/gateway-configs/{id}",
+ path_template("/v1/gateway-configs/{id}", id=id),
body=await async_maybe_transform(
{
"auth_mechanism": auth_mechanism,
@@ -480,6 +485,7 @@ 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,
@@ -497,6 +503,9 @@ def list(
Args:
id: Filter by 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 name (partial match supported).
@@ -522,6 +531,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -562,7 +572,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/gateway-configs/{id}/delete",
+ path_template("/v1/gateway-configs/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/mcp_configs.py b/src/runloop_api_client/resources/mcp_configs.py
index 24b05cc2d..b097db18b 100644
--- a/src/runloop_api_client/resources/mcp_configs.py
+++ b/src/runloop_api_client/resources/mcp_configs.py
@@ -8,7 +8,7 @@
from ..types import mcp_config_list_params, mcp_config_create_params, mcp_config_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -134,7 +134,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/mcp-configs/{id}",
+ path_template("/v1/mcp-configs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -184,7 +184,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/mcp-configs/{id}",
+ path_template("/v1/mcp-configs/{id}", id=id),
body=maybe_transform(
{
"allowed_tools": allowed_tools,
@@ -208,6 +208,7 @@ 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,
@@ -224,6 +225,9 @@ def list(
Args:
id: Filter by 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 name (prefix match supported).
@@ -249,6 +253,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -289,7 +294,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/mcp-configs/{id}/delete",
+ path_template("/v1/mcp-configs/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -411,7 +416,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/mcp-configs/{id}",
+ path_template("/v1/mcp-configs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -461,7 +466,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/mcp-configs/{id}",
+ path_template("/v1/mcp-configs/{id}", id=id),
body=await async_maybe_transform(
{
"allowed_tools": allowed_tools,
@@ -485,6 +490,7 @@ 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,
@@ -501,6 +507,9 @@ def list(
Args:
id: Filter by 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 name (prefix match supported).
@@ -526,6 +535,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -566,7 +576,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/mcp-configs/{id}/delete",
+ path_template("/v1/mcp-configs/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/network_policies.py b/src/runloop_api_client/resources/network_policies.py
index f50d4fe6d..7ba7abd9e 100644
--- a/src/runloop_api_client/resources/network_policies.py
+++ b/src/runloop_api_client/resources/network_policies.py
@@ -8,7 +8,7 @@
from ..types import network_policy_list_params, network_policy_create_params, network_policy_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -149,7 +149,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/network-policies/{id}",
+ path_template("/v1/network-policies/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -208,7 +208,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/network-policies/{id}",
+ path_template("/v1/network-policies/{id}", id=id),
body=maybe_transform(
{
"allow_agent_gateway": allow_agent_gateway,
@@ -235,6 +235,7 @@ 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,
@@ -251,6 +252,9 @@ def list(
Args:
id: Filter by 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 name (partial match supported).
@@ -276,6 +280,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -316,7 +321,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/network-policies/{id}/delete",
+ path_template("/v1/network-policies/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -453,7 +458,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/network-policies/{id}",
+ path_template("/v1/network-policies/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -512,7 +517,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/network-policies/{id}",
+ path_template("/v1/network-policies/{id}", id=id),
body=await async_maybe_transform(
{
"allow_agent_gateway": allow_agent_gateway,
@@ -539,6 +544,7 @@ 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,
@@ -555,6 +561,9 @@ def list(
Args:
id: Filter by 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 name (partial match supported).
@@ -580,6 +589,7 @@ def list(
query=maybe_transform(
{
"id": id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -620,7 +630,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/network-policies/{id}/delete",
+ path_template("/v1/network-policies/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/objects.py b/src/runloop_api_client/resources/objects.py
index 409d5f6f3..5df9476ec 100644
--- a/src/runloop_api_client/resources/objects.py
+++ b/src/runloop_api_client/resources/objects.py
@@ -9,7 +9,7 @@
from ..types import object_list_params, object_create_params, object_download_params, object_list_public_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -133,7 +133,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/objects/{id}",
+ path_template("/v1/objects/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -144,6 +144,7 @@ def list(
self,
*,
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"] | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
search: str | Omit = omit,
@@ -162,6 +163,9 @@ def list(
Args:
content_type: Filter storage objects by content type.
+ 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 storage objects by name (partial match supported).
@@ -191,6 +195,7 @@ def list(
query=maybe_transform(
{
"content_type": content_type,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"search": search,
@@ -234,7 +239,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/objects/{id}/delete",
+ path_template("/v1/objects/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -275,7 +280,7 @@ def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/objects/{id}/complete",
+ path_template("/v1/objects/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -317,7 +322,7 @@ def download(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/objects/{id}/download",
+ path_template("/v1/objects/{id}/download", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -334,6 +339,7 @@ def list_public(
self,
*,
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"] | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
search: str | Omit = omit,
@@ -352,6 +358,9 @@ def list_public(
Args:
content_type: Filter storage objects by content type.
+ 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 storage objects by name (partial match supported).
@@ -381,6 +390,7 @@ def list_public(
query=maybe_transform(
{
"content_type": content_type,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"search": search,
@@ -501,7 +511,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/objects/{id}",
+ path_template("/v1/objects/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -512,6 +522,7 @@ def list(
self,
*,
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"] | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
search: str | Omit = omit,
@@ -530,6 +541,9 @@ def list(
Args:
content_type: Filter storage objects by content type.
+ 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 storage objects by name (partial match supported).
@@ -559,6 +573,7 @@ def list(
query=maybe_transform(
{
"content_type": content_type,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"search": search,
@@ -602,7 +617,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/objects/{id}/delete",
+ path_template("/v1/objects/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -643,7 +658,7 @@ async def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/objects/{id}/complete",
+ path_template("/v1/objects/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -685,7 +700,7 @@ async def download(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/objects/{id}/download",
+ path_template("/v1/objects/{id}/download", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -702,6 +717,7 @@ def list_public(
self,
*,
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"] | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
search: str | Omit = omit,
@@ -720,6 +736,9 @@ def list_public(
Args:
content_type: Filter storage objects by content type.
+ 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 storage objects by name (partial match supported).
@@ -749,6 +768,7 @@ def list_public(
query=maybe_transform(
{
"content_type": content_type,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"search": search,
diff --git a/src/runloop_api_client/resources/repositories.py b/src/runloop_api_client/resources/repositories.py
index a22075540..5b961cf64 100644
--- a/src/runloop_api_client/resources/repositories.py
+++ b/src/runloop_api_client/resources/repositories.py
@@ -14,7 +14,7 @@
repository_refresh_params,
)
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -138,7 +138,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/repositories/{id}",
+ path_template("/v1/repositories/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -148,6 +148,7 @@ def retrieve(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
owner: str | Omit = omit,
@@ -163,6 +164,9 @@ def list(
List all available repository connections.
Args:
+ 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 repository name
@@ -189,6 +193,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"owner": owner,
@@ -230,7 +235,7 @@ def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/repositories/{id}/delete",
+ path_template("/v1/repositories/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -274,7 +279,7 @@ def inspect(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/repositories/{id}/inspect",
+ path_template("/v1/repositories/{id}/inspect", id=id),
body=maybe_transform(
{"github_auth_token": github_auth_token}, repository_inspect_params.RepositoryInspectParams
),
@@ -315,7 +320,7 @@ def list_inspections(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/repositories/{id}/inspections",
+ path_template("/v1/repositories/{id}/inspections", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -359,7 +364,7 @@ def refresh(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/repositories/{id}/refresh",
+ path_template("/v1/repositories/{id}/refresh", id=id),
body=maybe_transform(
{
"blueprint_id": blueprint_id,
@@ -403,7 +408,7 @@ def retrieve_inspection(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/repositories/inspections/{id}",
+ path_template("/v1/repositories/inspections/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -517,7 +522,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/repositories/{id}",
+ path_template("/v1/repositories/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -527,6 +532,7 @@ async def retrieve(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
owner: str | Omit = omit,
@@ -542,6 +548,9 @@ def list(
List all available repository connections.
Args:
+ 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 repository name
@@ -568,6 +577,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"owner": owner,
@@ -609,7 +619,7 @@ async def delete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/repositories/{id}/delete",
+ path_template("/v1/repositories/{id}/delete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -653,7 +663,7 @@ async def inspect(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/repositories/{id}/inspect",
+ path_template("/v1/repositories/{id}/inspect", id=id),
body=await async_maybe_transform(
{"github_auth_token": github_auth_token}, repository_inspect_params.RepositoryInspectParams
),
@@ -694,7 +704,7 @@ async def list_inspections(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/repositories/{id}/inspections",
+ path_template("/v1/repositories/{id}/inspections", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -738,7 +748,7 @@ async def refresh(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/repositories/{id}/refresh",
+ path_template("/v1/repositories/{id}/refresh", id=id),
body=await async_maybe_transform(
{
"blueprint_id": blueprint_id,
@@ -782,7 +792,7 @@ async def retrieve_inspection(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/repositories/inspections/{id}",
+ path_template("/v1/repositories/inspections/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
diff --git a/src/runloop_api_client/resources/scenarios/runs.py b/src/runloop_api_client/resources/scenarios/runs.py
index 3ea9a960f..67c5c4428 100644
--- a/src/runloop_api_client/resources/scenarios/runs.py
+++ b/src/runloop_api_client/resources/scenarios/runs.py
@@ -5,7 +5,7 @@
import httpx
from ..._types import NOT_GIVEN, Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform
+from ..._utils import path_template, maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -79,7 +79,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/scenarios/runs/{id}",
+ path_template("/v1/scenarios/runs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -90,6 +90,7 @@ def list(
self,
*,
benchmark_run_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
scenario_id: str | Omit = omit,
@@ -108,6 +109,9 @@ def list(
Args:
benchmark_run_id: Filter by benchmark run 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 name
@@ -137,6 +141,7 @@ def list(
query=maybe_transform(
{
"benchmark_run_id": benchmark_run_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"scenario_id": scenario_id,
@@ -180,7 +185,7 @@ def cancel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/runs/{id}/cancel",
+ path_template("/v1/scenarios/runs/{id}/cancel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -222,7 +227,7 @@ def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/runs/{id}/complete",
+ path_template("/v1/scenarios/runs/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -264,7 +269,7 @@ def download_logs(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {"Accept": "application/zip", **(extra_headers or {})}
return self._post(
- f"/v1/scenarios/runs/{id}/download_logs",
+ path_template("/v1/scenarios/runs/{id}/download_logs", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -304,7 +309,7 @@ def score(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/runs/{id}/score",
+ path_template("/v1/scenarios/runs/{id}/score", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -499,7 +504,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/scenarios/runs/{id}",
+ path_template("/v1/scenarios/runs/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -510,6 +515,7 @@ def list(
self,
*,
benchmark_run_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
scenario_id: str | Omit = omit,
@@ -528,6 +534,9 @@ def list(
Args:
benchmark_run_id: Filter by benchmark run 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 name
@@ -557,6 +566,7 @@ def list(
query=maybe_transform(
{
"benchmark_run_id": benchmark_run_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"scenario_id": scenario_id,
@@ -600,7 +610,7 @@ async def cancel(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/runs/{id}/cancel",
+ path_template("/v1/scenarios/runs/{id}/cancel", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -642,7 +652,7 @@ async def complete(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/runs/{id}/complete",
+ path_template("/v1/scenarios/runs/{id}/complete", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -684,7 +694,7 @@ async def download_logs(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {"Accept": "application/zip", **(extra_headers or {})}
return await self._post(
- f"/v1/scenarios/runs/{id}/download_logs",
+ path_template("/v1/scenarios/runs/{id}/download_logs", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -724,7 +734,7 @@ async def score(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/runs/{id}/score",
+ path_template("/v1/scenarios/runs/{id}/score", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/resources/scenarios/scenarios.py b/src/runloop_api_client/resources/scenarios/scenarios.py
index 5c31e4282..e3ce8c91b 100644
--- a/src/runloop_api_client/resources/scenarios/scenarios.py
+++ b/src/runloop_api_client/resources/scenarios/scenarios.py
@@ -31,7 +31,7 @@
AsyncScorersResourceWithStreamingResponse,
)
from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -197,7 +197,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/scenarios/{id}",
+ path_template("/v1/scenarios/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -268,7 +268,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/{id}",
+ path_template("/v1/scenarios/{id}", id=id),
body=maybe_transform(
{
"environment_parameters": environment_parameters,
@@ -298,6 +298,7 @@ def list(
self,
*,
benchmark_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -315,6 +316,9 @@ def list(
Args:
benchmark_id: Filter scenarios by benchmark 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: Query for Scenarios with a given name.
@@ -342,6 +346,7 @@ def list(
query=maybe_transform(
{
"benchmark_id": benchmark_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -384,7 +389,7 @@ def archive(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/{id}/archive",
+ path_template("/v1/scenarios/{id}/archive", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -398,6 +403,7 @@ def archive(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -412,6 +418,9 @@ def list_public(
List all public scenarios matching filter.
Args:
+ 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: Query for Scenarios with a given name.
@@ -436,6 +445,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -709,7 +719,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/scenarios/{id}",
+ path_template("/v1/scenarios/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -780,7 +790,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/{id}",
+ path_template("/v1/scenarios/{id}", id=id),
body=await async_maybe_transform(
{
"environment_parameters": environment_parameters,
@@ -810,6 +820,7 @@ def list(
self,
*,
benchmark_id: str | Omit = omit,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -827,6 +838,9 @@ def list(
Args:
benchmark_id: Filter scenarios by benchmark 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: Query for Scenarios with a given name.
@@ -854,6 +868,7 @@ def list(
query=maybe_transform(
{
"benchmark_id": benchmark_id,
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
@@ -896,7 +911,7 @@ async def archive(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/{id}/archive",
+ path_template("/v1/scenarios/{id}/archive", id=id),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -910,6 +925,7 @@ async def archive(
def list_public(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | Omit = omit,
name: str | Omit = omit,
starting_after: str | Omit = omit,
@@ -924,6 +940,9 @@ def list_public(
List all public scenarios matching filter.
Args:
+ 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: Query for Scenarios with a given name.
@@ -948,6 +967,7 @@ def list_public(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"name": name,
"starting_after": starting_after,
diff --git a/src/runloop_api_client/resources/scenarios/scorers.py b/src/runloop_api_client/resources/scenarios/scorers.py
index cdb011dc7..1472d86af 100644
--- a/src/runloop_api_client/resources/scenarios/scorers.py
+++ b/src/runloop_api_client/resources/scenarios/scorers.py
@@ -5,7 +5,7 @@
import httpx
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from ..._utils import maybe_transform, async_maybe_transform
+from ..._utils import path_template, maybe_transform, async_maybe_transform
from ..._compat import cached_property
from ..._resource import SyncAPIResource, AsyncAPIResource
from ..._response import (
@@ -122,7 +122,7 @@ def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._get(
- f"/v1/scenarios/scorers/{id}",
+ path_template("/v1/scenarios/scorers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -165,7 +165,7 @@ def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return self._post(
- f"/v1/scenarios/scorers/{id}",
+ path_template("/v1/scenarios/scorers/{id}", id=id),
body=maybe_transform(
{
"bash_script": bash_script,
@@ -186,6 +186,7 @@ def update(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | 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.
@@ -199,6 +200,9 @@ def list(
List all Scenario Scorers matching filter.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -221,6 +225,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
},
@@ -328,7 +333,7 @@ async def retrieve(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._get(
- f"/v1/scenarios/scorers/{id}",
+ path_template("/v1/scenarios/scorers/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
@@ -371,7 +376,7 @@ async def update(
if not id:
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
return await self._post(
- f"/v1/scenarios/scorers/{id}",
+ path_template("/v1/scenarios/scorers/{id}", id=id),
body=await async_maybe_transform(
{
"bash_script": bash_script,
@@ -392,6 +397,7 @@ async def update(
def list(
self,
*,
+ include_total_count: bool | Omit = omit,
limit: int | 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.
@@ -405,6 +411,9 @@ def list(
List all Scenario Scorers matching filter.
Args:
+ 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.
starting_after: Load the next page of data starting after the item with the given ID.
@@ -427,6 +436,7 @@ def list(
timeout=timeout,
query=maybe_transform(
{
+ "include_total_count": include_total_count,
"limit": limit,
"starting_after": starting_after,
},
diff --git a/src/runloop_api_client/resources/secrets.py b/src/runloop_api_client/resources/secrets.py
index fa7d45471..38a9d8fc0 100644
--- a/src/runloop_api_client/resources/secrets.py
+++ b/src/runloop_api_client/resources/secrets.py
@@ -6,7 +6,7 @@
from ..types import secret_list_params, secret_create_params, secret_update_params
from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
-from .._utils import maybe_transform, async_maybe_transform
+from .._utils import path_template, maybe_transform, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
@@ -164,7 +164,7 @@ def update(
if not name:
raise ValueError(f"Expected a non-empty value for `name` but received {name!r}")
return self._post(
- f"/v1/secrets/{name}",
+ path_template("/v1/secrets/{name}", name=name),
body=maybe_transform({"value": value}, secret_update_params.SecretUpdateParams),
options=make_request_options(
extra_headers=extra_headers,
@@ -246,7 +246,7 @@ def delete(
if not name:
raise ValueError(f"Expected a non-empty value for `name` but received {name!r}")
return self._post(
- f"/v1/secrets/{name}/delete",
+ path_template("/v1/secrets/{name}/delete", name=name),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
@@ -400,7 +400,7 @@ async def update(
if not name:
raise ValueError(f"Expected a non-empty value for `name` but received {name!r}")
return await self._post(
- f"/v1/secrets/{name}",
+ path_template("/v1/secrets/{name}", name=name),
body=await async_maybe_transform({"value": value}, secret_update_params.SecretUpdateParams),
options=make_request_options(
extra_headers=extra_headers,
@@ -482,7 +482,7 @@ async def delete(
if not name:
raise ValueError(f"Expected a non-empty value for `name` but received {name!r}")
return await self._post(
- f"/v1/secrets/{name}/delete",
+ path_template("/v1/secrets/{name}/delete", name=name),
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
diff --git a/src/runloop_api_client/sdk/_types.py b/src/runloop_api_client/sdk/_types.py
index c66efebe3..82e4bbb9a 100644
--- a/src/runloop_api_client/sdk/_types.py
+++ b/src/runloop_api_client/sdk/_types.py
@@ -26,7 +26,6 @@
NetworkPolicyListParams,
DevboxDownloadFileParams,
DevboxEnableTunnelParams,
- DevboxRemoveTunnelParams,
DevboxSnapshotDiskParams,
GatewayConfigCreateParams,
GatewayConfigUpdateParams,
@@ -127,7 +126,7 @@ class SDKDevboxEnableTunnelParams(DevboxEnableTunnelParams, LongRequestOptions):
pass
-class SDKDevboxRemoveTunnelParams(DevboxRemoveTunnelParams, LongRequestOptions):
+class SDKDevboxRemoveTunnelParams(LongRequestOptions):
pass
diff --git a/src/runloop_api_client/sdk/async_devbox.py b/src/runloop_api_client/sdk/async_devbox.py
index 9a97cb5f3..cdedcb5db 100644
--- a/src/runloop_api_client/sdk/async_devbox.py
+++ b/src/runloop_api_client/sdk/async_devbox.py
@@ -840,7 +840,7 @@ async def remove_tunnel(
:rtype: object
Example:
- >>> await devbox.net.remove_tunnel(port=8080)
+ >>> await devbox.net.remove_tunnel()
"""
warnings.warn(
"remove_tunnel is deprecated; V2 tunnels cannot be removed and close on devbox shutdown.",
diff --git a/src/runloop_api_client/sdk/devbox.py b/src/runloop_api_client/sdk/devbox.py
index ac1743a6b..aec345715 100644
--- a/src/runloop_api_client/sdk/devbox.py
+++ b/src/runloop_api_client/sdk/devbox.py
@@ -843,7 +843,7 @@ def remove_tunnel(
:rtype: object
Example:
- >>> devbox.net.remove_tunnel(port=8080)
+ >>> devbox.net.remove_tunnel()
"""
warnings.warn(
"remove_tunnel is deprecated; V2 tunnels cannot be removed and close on devbox shutdown.",
diff --git a/src/runloop_api_client/types/__init__.py b/src/runloop_api_client/types/__init__.py
index 693d5c6f8..11f82aa7a 100644
--- a/src/runloop_api_client/types/__init__.py
+++ b/src/runloop_api_client/types/__init__.py
@@ -12,6 +12,7 @@
LaunchParameters as LaunchParameters,
CodeMountParameters as CodeMountParameters,
)
+from .axon_view import AxonView as AxonView
from .agent_view import AgentView as AgentView
from .devbox_view import DevboxView as DevboxView
from .object_view import ObjectView as ObjectView
@@ -19,9 +20,11 @@
from .tunnel_view import TunnelView as TunnelView
from .input_context import InputContext as InputContext
from .scenario_view import ScenarioView as ScenarioView
+from .axon_list_view import AxonListView as AxonListView
from .benchmark_view import BenchmarkView as BenchmarkView
from .blueprint_view import BlueprintView as BlueprintView
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 .devbox_list_view import DevboxListView as DevboxListView
from .object_list_view import ObjectListView as ObjectListView
@@ -30,17 +33,20 @@
from .secret_list_view import SecretListView as SecretListView
from .agent_list_params import AgentListParams as AgentListParams
from .scenario_run_view import ScenarioRunView as ScenarioRunView
+from .axon_create_params import AxonCreateParams as AxonCreateParams
from .benchmark_job_view import BenchmarkJobView as BenchmarkJobView
from .benchmark_run_view import BenchmarkRunView as BenchmarkRunView
from .devbox_list_params import DevboxListParams as DevboxListParams
from .object_list_params import ObjectListParams as ObjectListParams
from .secret_list_params import SecretListParams as SecretListParams
from .agent_create_params import AgentCreateParams as AgentCreateParams
+from .axon_publish_params import AxonPublishParams as AxonPublishParams
from .blueprint_build_log import BlueprintBuildLog as BlueprintBuildLog
from .blueprint_list_view import BlueprintListView as BlueprintListView
from .gateway_config_view import GatewayConfigView as GatewayConfigView
from .input_context_param import InputContextParam as InputContextParam
from .network_policy_view import NetworkPolicyView as NetworkPolicyView
+from .publish_result_view import PublishResultView as PublishResultView
from .devbox_create_params import DevboxCreateParams as DevboxCreateParams
from .devbox_snapshot_view import DevboxSnapshotView as DevboxSnapshotView
from .devbox_update_params import DevboxUpdateParams as DevboxUpdateParams
@@ -99,7 +105,6 @@
from .devbox_download_file_params import DevboxDownloadFileParams as DevboxDownloadFileParams
from .devbox_enable_tunnel_params import DevboxEnableTunnelParams as DevboxEnableTunnelParams
from .devbox_execute_async_params import DevboxExecuteAsyncParams as DevboxExecuteAsyncParams
-from .devbox_remove_tunnel_params import DevboxRemoveTunnelParams as DevboxRemoveTunnelParams
from .devbox_snapshot_disk_params import DevboxSnapshotDiskParams as DevboxSnapshotDiskParams
from .scenario_list_public_params import ScenarioListPublicParams as ScenarioListPublicParams
from .benchmark_definitions_params import BenchmarkDefinitionsParams as BenchmarkDefinitionsParams
diff --git a/src/runloop_api_client/types/agent_list_params.py b/src/runloop_api_client/types/agent_list_params.py
index 3df89fc25..5c3857fb5 100644
--- a/src/runloop_api_client/types/agent_list_params.py
+++ b/src/runloop_api_client/types/agent_list_params.py
@@ -8,6 +8,12 @@
class AgentListParams(TypedDict, total=False):
+ 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.
+ """
+
is_public: bool
"""Filter agents by public visibility."""
diff --git a/src/runloop_api_client/types/agent_list_view.py b/src/runloop_api_client/types/agent_list_view.py
index 9e57a9769..f3dfbd09f 100644
--- a/src/runloop_api_client/types/agent_list_view.py
+++ b/src/runloop_api_client/types/agent_list_view.py
@@ -17,14 +17,5 @@ class AgentListView(BaseModel):
has_more: bool
"""Whether there are more Agents to fetch."""
- remaining_count: Optional[int] = None
- """The count of remaining Agents.
-
- Deprecated: will be removed in a future breaking change.
- """
-
total_count: Optional[int] = None
- """The total count of Agents.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """The total count of Agents."""
diff --git a/src/runloop_api_client/types/axon_create_params.py b/src/runloop_api_client/types/axon_create_params.py
new file mode 100644
index 000000000..0906db0ae
--- /dev/null
+++ b/src/runloop_api_client/types/axon_create_params.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import TypedDict
+
+__all__ = ["AxonCreateParams"]
+
+
+class AxonCreateParams(TypedDict, total=False):
+ name: Optional[str]
+ """(Optional) Name for the axon."""
diff --git a/src/runloop_api_client/types/axon_event_view.py b/src/runloop_api_client/types/axon_event_view.py
new file mode 100644
index 000000000..63f09b80a
--- /dev/null
+++ b/src/runloop_api_client/types/axon_event_view.py
@@ -0,0 +1,30 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["AxonEventView"]
+
+
+class AxonEventView(BaseModel):
+ axon_id: str
+ """The axon identifier."""
+
+ event_type: str
+ """Event type (e.g. push, pull_request)."""
+
+ origin: Literal["EXTERNAL_EVENT", "AGENT_EVENT", "USER_EVENT", "SYSTEM_EVENT"]
+ """Event origin."""
+
+ payload: str
+ """JSON-encoded event payload."""
+
+ sequence: int
+ """Monotonic sequence number."""
+
+ source: str
+ """Event source (e.g. github, slack)."""
+
+ timestamp_ms: int
+ """Timestamp in milliseconds since epoch."""
diff --git a/src/runloop_api_client/types/axon_list_view.py b/src/runloop_api_client/types/axon_list_view.py
new file mode 100644
index 000000000..bd6c4d31c
--- /dev/null
+++ b/src/runloop_api_client/types/axon_list_view.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from .._models import BaseModel
+from .axon_view import AxonView
+
+__all__ = ["AxonListView"]
+
+
+class AxonListView(BaseModel):
+ axons: List[AxonView]
+ """List of active axons."""
diff --git a/src/runloop_api_client/types/axon_publish_params.py b/src/runloop_api_client/types/axon_publish_params.py
new file mode 100644
index 000000000..98fcd91bf
--- /dev/null
+++ b/src/runloop_api_client/types/axon_publish_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, TypedDict
+
+__all__ = ["AxonPublishParams"]
+
+
+class AxonPublishParams(TypedDict, total=False):
+ event_type: Required[str]
+ """The event type (e.g. push, pull_request)."""
+
+ origin: Required[Literal["EXTERNAL_EVENT", "AGENT_EVENT", "USER_EVENT"]]
+ """Event origin."""
+
+ payload: Required[str]
+ """Event payload."""
+
+ source: Required[str]
+ """The source of the event (e.g. github, slack)."""
diff --git a/src/runloop_api_client/types/axon_view.py b/src/runloop_api_client/types/axon_view.py
new file mode 100644
index 000000000..61d1bd243
--- /dev/null
+++ b/src/runloop_api_client/types/axon_view.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from .._models import BaseModel
+
+__all__ = ["AxonView"]
+
+
+class AxonView(BaseModel):
+ id: str
+ """The axon identifier."""
+
+ created_at_ms: int
+ """Creation time in milliseconds since epoch."""
+
+ name: Optional[str] = None
+ """The name of the axon."""
diff --git a/src/runloop_api_client/types/benchmark_job_list_params.py b/src/runloop_api_client/types/benchmark_job_list_params.py
index c0db8843c..9ab17e8eb 100644
--- a/src/runloop_api_client/types/benchmark_job_list_params.py
+++ b/src/runloop_api_client/types/benchmark_job_list_params.py
@@ -8,6 +8,12 @@
class BenchmarkJobListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/benchmark_job_list_view.py b/src/runloop_api_client/types/benchmark_job_list_view.py
index f0e1da7d0..f4f2458c3 100644
--- a/src/runloop_api_client/types/benchmark_job_list_view.py
+++ b/src/runloop_api_client/types/benchmark_job_list_view.py
@@ -14,6 +14,4 @@ class BenchmarkJobListView(BaseModel):
jobs: List[BenchmarkJobView]
"""List of BenchmarkJobs matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/benchmark_list_params.py b/src/runloop_api_client/types/benchmark_list_params.py
index 4e8b0c78b..d8be9aeca 100644
--- a/src/runloop_api_client/types/benchmark_list_params.py
+++ b/src/runloop_api_client/types/benchmark_list_params.py
@@ -8,6 +8,12 @@
class BenchmarkListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/benchmark_list_public_params.py b/src/runloop_api_client/types/benchmark_list_public_params.py
index 6dec4283b..9be7ffdf4 100644
--- a/src/runloop_api_client/types/benchmark_list_public_params.py
+++ b/src/runloop_api_client/types/benchmark_list_public_params.py
@@ -8,6 +8,12 @@
class BenchmarkListPublicParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/benchmark_run_list_params.py b/src/runloop_api_client/types/benchmark_run_list_params.py
index 28d4e2e87..4f4c8a550 100644
--- a/src/runloop_api_client/types/benchmark_run_list_params.py
+++ b/src/runloop_api_client/types/benchmark_run_list_params.py
@@ -11,6 +11,12 @@ class BenchmarkRunListParams(TypedDict, total=False):
benchmark_id: str
"""The Benchmark ID to filter by."""
+ 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."""
diff --git a/src/runloop_api_client/types/benchmark_run_list_scenario_runs_params.py b/src/runloop_api_client/types/benchmark_run_list_scenario_runs_params.py
index c88c09167..dddfa256a 100644
--- a/src/runloop_api_client/types/benchmark_run_list_scenario_runs_params.py
+++ b/src/runloop_api_client/types/benchmark_run_list_scenario_runs_params.py
@@ -8,6 +8,12 @@
class BenchmarkRunListScenarioRunsParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/benchmark_run_list_view.py b/src/runloop_api_client/types/benchmark_run_list_view.py
index e85506bab..efee2176d 100644
--- a/src/runloop_api_client/types/benchmark_run_list_view.py
+++ b/src/runloop_api_client/types/benchmark_run_list_view.py
@@ -14,6 +14,4 @@ class BenchmarkRunListView(BaseModel):
runs: List[BenchmarkRunView]
"""List of BenchmarkRuns matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/blueprint_list_params.py b/src/runloop_api_client/types/blueprint_list_params.py
index f72de7d2f..c61df2640 100644
--- a/src/runloop_api_client/types/blueprint_list_params.py
+++ b/src/runloop_api_client/types/blueprint_list_params.py
@@ -8,6 +8,12 @@
class BlueprintListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/blueprint_list_public_params.py b/src/runloop_api_client/types/blueprint_list_public_params.py
index e0f224f32..a6b66dc9b 100644
--- a/src/runloop_api_client/types/blueprint_list_public_params.py
+++ b/src/runloop_api_client/types/blueprint_list_public_params.py
@@ -8,6 +8,12 @@
class BlueprintListPublicParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/blueprint_list_view.py b/src/runloop_api_client/types/blueprint_list_view.py
index 7d97314f5..e5eee905b 100644
--- a/src/runloop_api_client/types/blueprint_list_view.py
+++ b/src/runloop_api_client/types/blueprint_list_view.py
@@ -14,6 +14,4 @@ class BlueprintListView(BaseModel):
has_more: bool
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/devbox_list_disk_snapshots_params.py b/src/runloop_api_client/types/devbox_list_disk_snapshots_params.py
index d26c3fbd8..48e0fc9e3 100644
--- a/src/runloop_api_client/types/devbox_list_disk_snapshots_params.py
+++ b/src/runloop_api_client/types/devbox_list_disk_snapshots_params.py
@@ -13,6 +13,12 @@ class DevboxListDiskSnapshotsParams(TypedDict, total=False):
devbox_id: str
"""Devbox ID to filter by."""
+ 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."""
diff --git a/src/runloop_api_client/types/devbox_list_params.py b/src/runloop_api_client/types/devbox_list_params.py
index c508762da..d8bae28d7 100644
--- a/src/runloop_api_client/types/devbox_list_params.py
+++ b/src/runloop_api_client/types/devbox_list_params.py
@@ -8,6 +8,12 @@
class DevboxListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/devbox_list_view.py b/src/runloop_api_client/types/devbox_list_view.py
index 6bd522ee5..6380f9326 100644
--- a/src/runloop_api_client/types/devbox_list_view.py
+++ b/src/runloop_api_client/types/devbox_list_view.py
@@ -14,6 +14,4 @@ class DevboxListView(BaseModel):
has_more: bool
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/devbox_remove_tunnel_params.py b/src/runloop_api_client/types/devbox_remove_tunnel_params.py
deleted file mode 100644
index eb58e2702..000000000
--- a/src/runloop_api_client/types/devbox_remove_tunnel_params.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, TypedDict
-
-__all__ = ["DevboxRemoveTunnelParams"]
-
-
-class DevboxRemoveTunnelParams(TypedDict, total=False):
- port: Required[int]
- """Devbox port that tunnel will expose."""
diff --git a/src/runloop_api_client/types/devbox_snapshot_list_view.py b/src/runloop_api_client/types/devbox_snapshot_list_view.py
index ca54f2eb1..0fdfd0594 100644
--- a/src/runloop_api_client/types/devbox_snapshot_list_view.py
+++ b/src/runloop_api_client/types/devbox_snapshot_list_view.py
@@ -14,6 +14,4 @@ class DevboxSnapshotListView(BaseModel):
snapshots: List[DevboxSnapshotView]
"""List of snapshots matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/devboxes/disk_snapshot_list_params.py b/src/runloop_api_client/types/devboxes/disk_snapshot_list_params.py
index 73e60f457..7a00118e4 100644
--- a/src/runloop_api_client/types/devboxes/disk_snapshot_list_params.py
+++ b/src/runloop_api_client/types/devboxes/disk_snapshot_list_params.py
@@ -13,6 +13,12 @@ class DiskSnapshotListParams(TypedDict, total=False):
devbox_id: str
"""Devbox ID to filter by."""
+ 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."""
diff --git a/src/runloop_api_client/types/gateway_config_list_params.py b/src/runloop_api_client/types/gateway_config_list_params.py
index cc8706b95..ef69f83b4 100644
--- a/src/runloop_api_client/types/gateway_config_list_params.py
+++ b/src/runloop_api_client/types/gateway_config_list_params.py
@@ -11,6 +11,12 @@ class GatewayConfigListParams(TypedDict, total=False):
id: str
"""Filter by 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."""
diff --git a/src/runloop_api_client/types/gateway_config_list_view.py b/src/runloop_api_client/types/gateway_config_list_view.py
index 05511971f..745e6376b 100644
--- a/src/runloop_api_client/types/gateway_config_list_view.py
+++ b/src/runloop_api_client/types/gateway_config_list_view.py
@@ -18,7 +18,4 @@ class GatewayConfigListView(BaseModel):
"""Whether there are more results available beyond this page."""
total_count: Optional[int] = None
- """Total count of GatewayConfigs that match the query.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """Total count of GatewayConfigs that match the query."""
diff --git a/src/runloop_api_client/types/mcp_config_list_params.py b/src/runloop_api_client/types/mcp_config_list_params.py
index 8b786ba13..684de89ec 100644
--- a/src/runloop_api_client/types/mcp_config_list_params.py
+++ b/src/runloop_api_client/types/mcp_config_list_params.py
@@ -11,6 +11,12 @@ class McpConfigListParams(TypedDict, total=False):
id: str
"""Filter by 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."""
diff --git a/src/runloop_api_client/types/mcp_config_list_view.py b/src/runloop_api_client/types/mcp_config_list_view.py
index 4992698c5..ed742162d 100644
--- a/src/runloop_api_client/types/mcp_config_list_view.py
+++ b/src/runloop_api_client/types/mcp_config_list_view.py
@@ -18,7 +18,4 @@ class McpConfigListView(BaseModel):
"""The list of McpConfigs."""
total_count: Optional[int] = None
- """Total count of McpConfigs that match the query.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """Total count of McpConfigs that match the query."""
diff --git a/src/runloop_api_client/types/network_policy_list_params.py b/src/runloop_api_client/types/network_policy_list_params.py
index 160da795f..cdbc84f1a 100644
--- a/src/runloop_api_client/types/network_policy_list_params.py
+++ b/src/runloop_api_client/types/network_policy_list_params.py
@@ -11,6 +11,12 @@ class NetworkPolicyListParams(TypedDict, total=False):
id: str
"""Filter by 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."""
diff --git a/src/runloop_api_client/types/network_policy_list_view.py b/src/runloop_api_client/types/network_policy_list_view.py
index ba031d0a9..2530a3699 100644
--- a/src/runloop_api_client/types/network_policy_list_view.py
+++ b/src/runloop_api_client/types/network_policy_list_view.py
@@ -18,7 +18,4 @@ class NetworkPolicyListView(BaseModel):
"""The list of NetworkPolicies."""
total_count: Optional[int] = None
- """Total count of items in this response.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """Total count of items in this response."""
diff --git a/src/runloop_api_client/types/object_list_params.py b/src/runloop_api_client/types/object_list_params.py
index eca1c7cdd..5ec2e88bc 100644
--- a/src/runloop_api_client/types/object_list_params.py
+++ b/src/runloop_api_client/types/object_list_params.py
@@ -11,6 +11,12 @@ class ObjectListParams(TypedDict, total=False):
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"]
"""Filter storage objects by content type."""
+ 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."""
diff --git a/src/runloop_api_client/types/object_list_public_params.py b/src/runloop_api_client/types/object_list_public_params.py
index 67475b263..a0b53dcd6 100644
--- a/src/runloop_api_client/types/object_list_public_params.py
+++ b/src/runloop_api_client/types/object_list_public_params.py
@@ -11,6 +11,12 @@ class ObjectListPublicParams(TypedDict, total=False):
content_type: Literal["unspecified", "text", "binary", "gzip", "tar", "tgz"]
"""Filter storage objects by content type."""
+ 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."""
diff --git a/src/runloop_api_client/types/object_list_view.py b/src/runloop_api_client/types/object_list_view.py
index 689c0899b..4b2658c1f 100644
--- a/src/runloop_api_client/types/object_list_view.py
+++ b/src/runloop_api_client/types/object_list_view.py
@@ -17,14 +17,5 @@ class ObjectListView(BaseModel):
objects: List[ObjectView]
"""List of Object entities."""
- remaining_count: Optional[int] = None
- """Number of Objects remaining after this page.
-
- Deprecated: will be removed in a future breaking change.
- """
-
total_count: Optional[int] = None
- """Total number of Objects across all pages.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """Total number of Objects across all pages."""
diff --git a/src/runloop_api_client/types/publish_result_view.py b/src/runloop_api_client/types/publish_result_view.py
new file mode 100644
index 000000000..f74e56a65
--- /dev/null
+++ b/src/runloop_api_client/types/publish_result_view.py
@@ -0,0 +1,13 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["PublishResultView"]
+
+
+class PublishResultView(BaseModel):
+ sequence: int
+ """Assigned sequence number."""
+
+ timestamp_ms: int
+ """Timestamp in milliseconds since epoch."""
diff --git a/src/runloop_api_client/types/repository_connection_list_view.py b/src/runloop_api_client/types/repository_connection_list_view.py
index eea040bc4..3146f27fd 100644
--- a/src/runloop_api_client/types/repository_connection_list_view.py
+++ b/src/runloop_api_client/types/repository_connection_list_view.py
@@ -14,6 +14,4 @@ class RepositoryConnectionListView(BaseModel):
repositories: List[RepositoryConnectionView]
"""List of repositories matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/repository_list_params.py b/src/runloop_api_client/types/repository_list_params.py
index d5f7b248a..813842cab 100644
--- a/src/runloop_api_client/types/repository_list_params.py
+++ b/src/runloop_api_client/types/repository_list_params.py
@@ -8,6 +8,12 @@
class RepositoryListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/scenario_definition_list_view.py b/src/runloop_api_client/types/scenario_definition_list_view.py
index f39cf1ed9..25bad1da5 100644
--- a/src/runloop_api_client/types/scenario_definition_list_view.py
+++ b/src/runloop_api_client/types/scenario_definition_list_view.py
@@ -14,6 +14,4 @@ class ScenarioDefinitionListView(BaseModel):
scenarios: List[ScenarioView]
"""List of Scenarios matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/scenario_list_params.py b/src/runloop_api_client/types/scenario_list_params.py
index 45ff3a87b..3d34d711a 100644
--- a/src/runloop_api_client/types/scenario_list_params.py
+++ b/src/runloop_api_client/types/scenario_list_params.py
@@ -11,6 +11,12 @@ class ScenarioListParams(TypedDict, total=False):
benchmark_id: str
"""Filter scenarios by benchmark 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."""
diff --git a/src/runloop_api_client/types/scenario_list_public_params.py b/src/runloop_api_client/types/scenario_list_public_params.py
index be7e40b8d..a2e71da64 100644
--- a/src/runloop_api_client/types/scenario_list_public_params.py
+++ b/src/runloop_api_client/types/scenario_list_public_params.py
@@ -8,6 +8,12 @@
class ScenarioListPublicParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/scenario_run_list_view.py b/src/runloop_api_client/types/scenario_run_list_view.py
index 142292dda..6083dbde2 100644
--- a/src/runloop_api_client/types/scenario_run_list_view.py
+++ b/src/runloop_api_client/types/scenario_run_list_view.py
@@ -14,6 +14,4 @@ class ScenarioRunListView(BaseModel):
runs: List[ScenarioRunView]
"""List of ScenarioRuns matching filter."""
- remaining_count: Optional[int] = None
-
total_count: Optional[int] = None
diff --git a/src/runloop_api_client/types/scenarios/run_list_params.py b/src/runloop_api_client/types/scenarios/run_list_params.py
index 97eeb425a..6e7373a07 100644
--- a/src/runloop_api_client/types/scenarios/run_list_params.py
+++ b/src/runloop_api_client/types/scenarios/run_list_params.py
@@ -11,6 +11,12 @@ class RunListParams(TypedDict, total=False):
benchmark_run_id: str
"""Filter by benchmark run 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."""
diff --git a/src/runloop_api_client/types/scenarios/scorer_list_params.py b/src/runloop_api_client/types/scenarios/scorer_list_params.py
index f80e7f6ac..a387f1a86 100644
--- a/src/runloop_api_client/types/scenarios/scorer_list_params.py
+++ b/src/runloop_api_client/types/scenarios/scorer_list_params.py
@@ -8,6 +8,12 @@
class ScorerListParams(TypedDict, total=False):
+ 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."""
diff --git a/src/runloop_api_client/types/secret_list_view.py b/src/runloop_api_client/types/secret_list_view.py
index 2f10bae2c..bb6b69d12 100644
--- a/src/runloop_api_client/types/secret_list_view.py
+++ b/src/runloop_api_client/types/secret_list_view.py
@@ -17,14 +17,5 @@ class SecretListView(BaseModel):
secrets: List[SecretView]
"""List of Secret objects. Values are omitted for security."""
- remaining_count: Optional[int] = None
- """Number of Secrets remaining after this page.
-
- Deprecated: will be removed in a future breaking change.
- """
-
total_count: Optional[int] = None
- """Total number of Secrets across all pages.
-
- Deprecated: will be removed in a future breaking change.
- """
+ """Total number of Secrets across all pages."""
diff --git a/src/runloop_api_client/types/shared/launch_parameters.py b/src/runloop_api_client/types/shared/launch_parameters.py
index 0264fa5c8..7c1fdc2a7 100644
--- a/src/runloop_api_client/types/shared/launch_parameters.py
+++ b/src/runloop_api_client/types/shared/launch_parameters.py
@@ -37,10 +37,9 @@ class LaunchParameters(BaseModel):
"""The target architecture for the Devbox. If unset, defaults to x86_64."""
available_ports: Optional[List[int]] = None
- """A list of ports to make available on the Devbox.
+ """[Deprecated] A list of ports to make available on the Devbox.
- Only ports made available will be surfaced to create tunnels via the
- 'createTunnel' API.
+ This field is ignored.
"""
custom_cpu_cores: Optional[int] = None
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 5c785b9f9..c30f90d86 100644
--- a/src/runloop_api_client/types/shared_params/launch_parameters.py
+++ b/src/runloop_api_client/types/shared_params/launch_parameters.py
@@ -39,10 +39,9 @@ class LaunchParameters(TypedDict, total=False):
"""The target architecture for the Devbox. If unset, defaults to x86_64."""
available_ports: Optional[Iterable[int]]
- """A list of ports to make available on the Devbox.
+ """[Deprecated] A list of ports to make available on the Devbox.
- Only ports made available will be surfaced to create tunnels via the
- 'createTunnel' API.
+ This field is ignored.
"""
custom_cpu_cores: Optional[int]
diff --git a/tests/api_resources/devboxes/test_disk_snapshots.py b/tests/api_resources/devboxes/test_disk_snapshots.py
index 170e618ba..3d861089e 100644
--- a/tests/api_resources/devboxes/test_disk_snapshots.py
+++ b/tests/api_resources/devboxes/test_disk_snapshots.py
@@ -81,6 +81,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
disk_snapshot = client.devboxes.disk_snapshots.list(
devbox_id="devbox_id",
+ include_total_count=True,
limit=0,
metadata_key="metadata[key]",
metadata_key_in="metadata[key][in]",
@@ -354,6 +355,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
disk_snapshot = await async_client.devboxes.disk_snapshots.list(
devbox_id="devbox_id",
+ include_total_count=True,
limit=0,
metadata_key="metadata[key]",
metadata_key_in="metadata[key][in]",
diff --git a/tests/api_resources/scenarios/test_runs.py b/tests/api_resources/scenarios/test_runs.py
index f3ac8eb88..429a815ee 100644
--- a/tests/api_resources/scenarios/test_runs.py
+++ b/tests/api_resources/scenarios/test_runs.py
@@ -73,6 +73,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
run = client.scenarios.runs.list(
benchmark_run_id="benchmark_run_id",
+ include_total_count=True,
limit=0,
name="name",
scenario_id="scenario_id",
@@ -324,6 +325,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
run = await async_client.scenarios.runs.list(
benchmark_run_id="benchmark_run_id",
+ include_total_count=True,
limit=0,
name="name",
scenario_id="scenario_id",
diff --git a/tests/api_resources/scenarios/test_scorers.py b/tests/api_resources/scenarios/test_scorers.py
index 359e0dcc7..cd15e860d 100644
--- a/tests/api_resources/scenarios/test_scorers.py
+++ b/tests/api_resources/scenarios/test_scorers.py
@@ -149,6 +149,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
scorer = client.scenarios.scorers.list(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
)
@@ -306,6 +307,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
scorer = await async_client.scenarios.scorers.list(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
)
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
index 693eec250..a6304d70d 100644
--- a/tests/api_resources/test_agents.py
+++ b/tests/api_resources/test_agents.py
@@ -128,6 +128,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
agent = client.agents.list(
+ include_total_count=True,
is_public=True,
limit=0,
name="name",
@@ -273,6 +274,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
agent = await async_client.agents.list(
+ include_total_count=True,
is_public=True,
limit=0,
name="name",
diff --git a/tests/api_resources/test_axons.py b/tests/api_resources/test_axons.py
new file mode 100644
index 000000000..bda5f1a23
--- /dev/null
+++ b/tests/api_resources/test_axons.py
@@ -0,0 +1,396 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from tests.utils import assert_matches_type
+from runloop_api_client import Runloop, AsyncRunloop
+from runloop_api_client.types import AxonView, AxonListView, PublishResultView
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAxons:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: Runloop) -> None:
+ axon = client.axons.create()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: Runloop) -> None:
+ axon = client.axons.create(
+ name="name",
+ )
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: Runloop) -> None:
+ response = client.axons.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: Runloop) -> None:
+ with client.axons.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_retrieve(self, client: Runloop) -> None:
+ axon = client.axons.retrieve(
+ "id",
+ )
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Runloop) -> None:
+ response = client.axons.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Runloop) -> None:
+ with client.axons.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: Runloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.axons.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ def test_method_list(self, client: Runloop) -> None:
+ axon = client.axons.list()
+ assert_matches_type(AxonListView, axon, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: Runloop) -> None:
+ response = client.axons.with_raw_response.list()
+
+ 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"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: Runloop) -> None:
+ with client.axons.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = response.parse()
+ assert_matches_type(AxonListView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_publish(self, client: Runloop) -> None:
+ axon = client.axons.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ @parametrize
+ def test_raw_response_publish(self, client: Runloop) -> None:
+ response = client.axons.with_raw_response.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = response.parse()
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ @parametrize
+ def test_streaming_response_publish(self, client: Runloop) -> None:
+ with client.axons.with_streaming_response.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = response.parse()
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_publish(self, client: Runloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.axons.with_raw_response.publish(
+ id="",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+
+ @parametrize
+ def test_method_subscribe_sse(self, client: Runloop) -> None:
+ axon_stream = client.axons.subscribe_sse(
+ "id",
+ )
+ axon_stream.response.close()
+
+ @parametrize
+ def test_raw_response_subscribe_sse(self, client: Runloop) -> None:
+ response = client.axons.with_raw_response.subscribe_sse(
+ "id",
+ )
+
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stream = response.parse()
+ stream.close()
+
+ @parametrize
+ def test_streaming_response_subscribe_sse(self, client: Runloop) -> None:
+ with client.axons.with_streaming_response.subscribe_sse(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stream = response.parse()
+ stream.close()
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_subscribe_sse(self, client: Runloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.axons.with_raw_response.subscribe_sse(
+ "",
+ )
+
+
+class TestAsyncAxons:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.create()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.create(
+ name="name",
+ )
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.axons.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = await response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncRunloop) -> None:
+ async with async_client.axons.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = await response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.retrieve(
+ "id",
+ )
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.axons.with_raw_response.retrieve(
+ "id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = await response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunloop) -> None:
+ async with async_client.axons.with_streaming_response.retrieve(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = await response.parse()
+ assert_matches_type(AxonView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncRunloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.axons.with_raw_response.retrieve(
+ "",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.list()
+ assert_matches_type(AxonListView, axon, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.axons.with_raw_response.list()
+
+ 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"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncRunloop) -> None:
+ async with async_client.axons.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = await response.parse()
+ assert_matches_type(AxonListView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_publish(self, async_client: AsyncRunloop) -> None:
+ axon = await async_client.axons.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ @parametrize
+ async def test_raw_response_publish(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.axons.with_raw_response.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ axon = await response.parse()
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_publish(self, async_client: AsyncRunloop) -> None:
+ async with async_client.axons.with_streaming_response.publish(
+ id="id",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ axon = await response.parse()
+ assert_matches_type(PublishResultView, axon, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_publish(self, async_client: AsyncRunloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.axons.with_raw_response.publish(
+ id="",
+ event_type="event_type",
+ origin="EXTERNAL_EVENT",
+ payload="payload",
+ source="source",
+ )
+
+ @parametrize
+ async def test_method_subscribe_sse(self, async_client: AsyncRunloop) -> None:
+ axon_stream = await async_client.axons.subscribe_sse(
+ "id",
+ )
+ await axon_stream.response.aclose()
+
+ @parametrize
+ async def test_raw_response_subscribe_sse(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.axons.with_raw_response.subscribe_sse(
+ "id",
+ )
+
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stream = await response.parse()
+ await stream.close()
+
+ @parametrize
+ async def test_streaming_response_subscribe_sse(self, async_client: AsyncRunloop) -> None:
+ async with async_client.axons.with_streaming_response.subscribe_sse(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stream = await response.parse()
+ await stream.close()
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_subscribe_sse(self, async_client: AsyncRunloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.axons.with_raw_response.subscribe_sse(
+ "",
+ )
diff --git a/tests/api_resources/test_benchmark_jobs.py b/tests/api_resources/test_benchmark_jobs.py
index 461943458..9b577a0c2 100644
--- a/tests/api_resources/test_benchmark_jobs.py
+++ b/tests/api_resources/test_benchmark_jobs.py
@@ -102,6 +102,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
benchmark_job = client.benchmark_jobs.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -216,6 +217,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
benchmark_job = await async_client.benchmark_jobs.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/api_resources/test_benchmark_runs.py b/tests/api_resources/test_benchmark_runs.py
index 854a44574..5e8709aff 100644
--- a/tests/api_resources/test_benchmark_runs.py
+++ b/tests/api_resources/test_benchmark_runs.py
@@ -68,6 +68,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
benchmark_run = client.benchmark_runs.list(
benchmark_id="benchmark_id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -181,6 +182,7 @@ def test_method_list_scenario_runs(self, client: Runloop) -> None:
def test_method_list_scenario_runs_with_all_params(self, client: Runloop) -> None:
benchmark_run = client.benchmark_runs.list_scenario_runs(
id="id",
+ include_total_count=True,
limit=0,
starting_after="starting_after",
state="running",
@@ -271,6 +273,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
benchmark_run = await async_client.benchmark_runs.list(
benchmark_id="benchmark_id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -384,6 +387,7 @@ async def test_method_list_scenario_runs(self, async_client: AsyncRunloop) -> No
async def test_method_list_scenario_runs_with_all_params(self, async_client: AsyncRunloop) -> None:
benchmark_run = await async_client.benchmark_runs.list_scenario_runs(
id="id",
+ include_total_count=True,
limit=0,
starting_after="starting_after",
state="running",
diff --git a/tests/api_resources/test_benchmarks.py b/tests/api_resources/test_benchmarks.py
index 803c75c60..2e1909775 100644
--- a/tests/api_resources/test_benchmarks.py
+++ b/tests/api_resources/test_benchmarks.py
@@ -164,6 +164,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
benchmark = client.benchmarks.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -245,6 +246,7 @@ def test_method_list_public(self, client: Runloop) -> None:
@parametrize
def test_method_list_public_with_all_params(self, client: Runloop) -> None:
benchmark = client.benchmarks.list_public(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
)
@@ -537,6 +539,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
benchmark = await async_client.benchmarks.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -618,6 +621,7 @@ async def test_method_list_public(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_public_with_all_params(self, async_client: AsyncRunloop) -> None:
benchmark = await async_client.benchmarks.list_public(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
)
diff --git a/tests/api_resources/test_blueprints.py b/tests/api_resources/test_blueprints.py
index d325ea2db..7ae5fada4 100644
--- a/tests/api_resources/test_blueprints.py
+++ b/tests/api_resources/test_blueprints.py
@@ -182,6 +182,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
blueprint = client.blueprints.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -325,6 +326,7 @@ def test_method_list_public(self, client: Runloop) -> None:
@parametrize
def test_method_list_public_with_all_params(self, client: Runloop) -> None:
blueprint = client.blueprints.list_public(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -648,6 +650,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
blueprint = await async_client.blueprints.list(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -791,6 +794,7 @@ async def test_method_list_public(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_public_with_all_params(self, async_client: AsyncRunloop) -> None:
blueprint = await async_client.blueprints.list_public(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py
index b7eaeb2f0..ab78cd157 100644
--- a/tests/api_resources/test_devboxes.py
+++ b/tests/api_resources/test_devboxes.py
@@ -230,6 +230,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
devbox = client.devboxes.list(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
status="provisioning",
@@ -653,6 +654,7 @@ def test_method_list_disk_snapshots(self, client: Runloop) -> None:
def test_method_list_disk_snapshots_with_all_params(self, client: Runloop) -> None:
devbox = client.devboxes.list_disk_snapshots(
devbox_id="devbox_id",
+ include_total_count=True,
limit=0,
metadata_key="metadata[key]",
metadata_key_in="metadata[key][in]",
@@ -725,21 +727,16 @@ def test_path_params_read_file_contents(self, client: Runloop) -> None:
@parametrize
def test_method_remove_tunnel(self, client: Runloop) -> None:
- with pytest.warns(DeprecationWarning):
- devbox = client.devboxes.remove_tunnel(
- id="id",
- port=0,
- )
-
+ devbox = client.devboxes.remove_tunnel(
+ "id",
+ )
assert_matches_type(object, devbox, path=["response"])
@parametrize
def test_raw_response_remove_tunnel(self, client: Runloop) -> None:
- with pytest.warns(DeprecationWarning):
- response = client.devboxes.with_raw_response.remove_tunnel(
- id="id",
- port=0,
- )
+ response = client.devboxes.with_raw_response.remove_tunnel(
+ "id",
+ )
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -748,27 +745,23 @@ def test_raw_response_remove_tunnel(self, client: Runloop) -> None:
@parametrize
def test_streaming_response_remove_tunnel(self, client: Runloop) -> None:
- with pytest.warns(DeprecationWarning):
- with client.devboxes.with_streaming_response.remove_tunnel(
- id="id",
- port=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ with client.devboxes.with_streaming_response.remove_tunnel(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- devbox = response.parse()
- assert_matches_type(object, devbox, path=["response"])
+ devbox = response.parse()
+ assert_matches_type(object, devbox, path=["response"])
assert cast(Any, response.is_closed) is True
@parametrize
def test_path_params_remove_tunnel(self, client: Runloop) -> None:
- with pytest.warns(DeprecationWarning):
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- client.devboxes.with_raw_response.remove_tunnel(
- id="",
- port=0,
- )
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ client.devboxes.with_raw_response.remove_tunnel(
+ "",
+ )
@parametrize
def test_method_resume(self, client: Runloop) -> None:
@@ -1851,6 +1844,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
devbox = await async_client.devboxes.list(
+ include_total_count=True,
limit=0,
starting_after="starting_after",
status="provisioning",
@@ -2274,6 +2268,7 @@ async def test_method_list_disk_snapshots(self, async_client: AsyncRunloop) -> N
async def test_method_list_disk_snapshots_with_all_params(self, async_client: AsyncRunloop) -> None:
devbox = await async_client.devboxes.list_disk_snapshots(
devbox_id="devbox_id",
+ include_total_count=True,
limit=0,
metadata_key="metadata[key]",
metadata_key_in="metadata[key][in]",
@@ -2346,21 +2341,16 @@ async def test_path_params_read_file_contents(self, async_client: AsyncRunloop)
@parametrize
async def test_method_remove_tunnel(self, async_client: AsyncRunloop) -> None:
- with pytest.warns(DeprecationWarning):
- devbox = await async_client.devboxes.remove_tunnel(
- id="id",
- port=0,
- )
-
+ devbox = await async_client.devboxes.remove_tunnel(
+ "id",
+ )
assert_matches_type(object, devbox, path=["response"])
@parametrize
async def test_raw_response_remove_tunnel(self, async_client: AsyncRunloop) -> None:
- with pytest.warns(DeprecationWarning):
- response = await async_client.devboxes.with_raw_response.remove_tunnel(
- id="id",
- port=0,
- )
+ response = await async_client.devboxes.with_raw_response.remove_tunnel(
+ "id",
+ )
assert response.is_closed is True
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
@@ -2369,27 +2359,23 @@ async def test_raw_response_remove_tunnel(self, async_client: AsyncRunloop) -> N
@parametrize
async def test_streaming_response_remove_tunnel(self, async_client: AsyncRunloop) -> None:
- with pytest.warns(DeprecationWarning):
- async with async_client.devboxes.with_streaming_response.remove_tunnel(
- id="id",
- port=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ async with async_client.devboxes.with_streaming_response.remove_tunnel(
+ "id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- devbox = await response.parse()
- assert_matches_type(object, devbox, path=["response"])
+ devbox = await response.parse()
+ assert_matches_type(object, devbox, path=["response"])
assert cast(Any, response.is_closed) is True
@parametrize
async def test_path_params_remove_tunnel(self, async_client: AsyncRunloop) -> None:
- with pytest.warns(DeprecationWarning):
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
- await async_client.devboxes.with_raw_response.remove_tunnel(
- id="",
- port=0,
- )
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"):
+ await async_client.devboxes.with_raw_response.remove_tunnel(
+ "",
+ )
@parametrize
async def test_method_resume(self, async_client: AsyncRunloop) -> None:
diff --git a/tests/api_resources/test_gateway_configs.py b/tests/api_resources/test_gateway_configs.py
index 6265b9875..5a60422dd 100644
--- a/tests/api_resources/test_gateway_configs.py
+++ b/tests/api_resources/test_gateway_configs.py
@@ -169,6 +169,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
gateway_config = client.gateway_configs.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -388,6 +389,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
gateway_config = await async_client.gateway_configs.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/api_resources/test_mcp_configs.py b/tests/api_resources/test_mcp_configs.py
index 0d3135668..ea6ed337c 100644
--- a/tests/api_resources/test_mcp_configs.py
+++ b/tests/api_resources/test_mcp_configs.py
@@ -163,6 +163,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
mcp_config = client.mcp_configs.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -376,6 +377,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
mcp_config = await async_client.mcp_configs.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/api_resources/test_network_policies.py b/tests/api_resources/test_network_policies.py
index 6a1587cb9..e7b5fb038 100644
--- a/tests/api_resources/test_network_policies.py
+++ b/tests/api_resources/test_network_policies.py
@@ -163,6 +163,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
network_policy = client.network_policies.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -376,6 +377,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
network_policy = await async_client.network_policies.list(
id="id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/api_resources/test_objects.py b/tests/api_resources/test_objects.py
index 2593e03bf..ca5d06651 100644
--- a/tests/api_resources/test_objects.py
+++ b/tests/api_resources/test_objects.py
@@ -112,6 +112,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
object_ = client.objects.list(
content_type="unspecified",
+ include_total_count=True,
limit=0,
name="name",
search="search",
@@ -271,6 +272,7 @@ def test_method_list_public(self, client: Runloop) -> None:
def test_method_list_public_with_all_params(self, client: Runloop) -> None:
object_ = client.objects.list_public(
content_type="unspecified",
+ include_total_count=True,
limit=0,
name="name",
search="search",
@@ -396,6 +398,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
object_ = await async_client.objects.list(
content_type="unspecified",
+ include_total_count=True,
limit=0,
name="name",
search="search",
@@ -555,6 +558,7 @@ async def test_method_list_public(self, async_client: AsyncRunloop) -> None:
async def test_method_list_public_with_all_params(self, async_client: AsyncRunloop) -> None:
object_ = await async_client.objects.list_public(
content_type="unspecified",
+ include_total_count=True,
limit=0,
name="name",
search="search",
diff --git a/tests/api_resources/test_repositories.py b/tests/api_resources/test_repositories.py
index 282688d80..20fa91e6d 100644
--- a/tests/api_resources/test_repositories.py
+++ b/tests/api_resources/test_repositories.py
@@ -114,6 +114,7 @@ def test_method_list(self, client: Runloop) -> None:
@parametrize
def test_method_list_with_all_params(self, client: Runloop) -> None:
repository = client.repositories.list(
+ include_total_count=True,
limit=0,
name="name",
owner="owner",
@@ -451,6 +452,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
repository = await async_client.repositories.list(
+ include_total_count=True,
limit=0,
name="name",
owner="owner",
diff --git a/tests/api_resources/test_scenarios.py b/tests/api_resources/test_scenarios.py
index 736a8395c..8182687c0 100644
--- a/tests/api_resources/test_scenarios.py
+++ b/tests/api_resources/test_scenarios.py
@@ -292,6 +292,7 @@ def test_method_list(self, client: Runloop) -> None:
def test_method_list_with_all_params(self, client: Runloop) -> None:
scenario = client.scenarios.list(
benchmark_id="benchmark_id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -365,6 +366,7 @@ def test_method_list_public(self, client: Runloop) -> None:
@parametrize
def test_method_list_public_with_all_params(self, client: Runloop) -> None:
scenario = client.scenarios.list_public(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -741,6 +743,7 @@ async def test_method_list(self, async_client: AsyncRunloop) -> None:
async def test_method_list_with_all_params(self, async_client: AsyncRunloop) -> None:
scenario = await async_client.scenarios.list(
benchmark_id="benchmark_id",
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
@@ -814,6 +817,7 @@ async def test_method_list_public(self, async_client: AsyncRunloop) -> None:
@parametrize
async def test_method_list_public_with_all_params(self, async_client: AsyncRunloop) -> None:
scenario = await async_client.scenarios.list_public(
+ include_total_count=True,
limit=0,
name="name",
starting_after="starting_after",
diff --git a/tests/sdk/async_devbox/test_interfaces.py b/tests/sdk/async_devbox/test_interfaces.py
index 7e766ea06..79376132e 100644
--- a/tests/sdk/async_devbox/test_interfaces.py
+++ b/tests/sdk/async_devbox/test_interfaces.py
@@ -186,7 +186,6 @@ async def test_remove_tunnel(self, mock_async_client: AsyncMock) -> None:
devbox = AsyncDevbox(mock_async_client, "dbx_123")
with pytest.warns(DeprecationWarning, match="remove_tunnel is deprecated"):
result = await devbox.net.remove_tunnel(
- port=8080,
extra_headers={"X-Custom": "value"},
extra_query={"param": "value"},
extra_body={"key": "value"},
diff --git a/tests/sdk/devbox/test_interfaces.py b/tests/sdk/devbox/test_interfaces.py
index 401849f28..7d0c1d567 100644
--- a/tests/sdk/devbox/test_interfaces.py
+++ b/tests/sdk/devbox/test_interfaces.py
@@ -287,7 +287,6 @@ def test_remove_tunnel(self, mock_client: Mock) -> None:
devbox = Devbox(mock_client, "dbx_123")
with pytest.warns(DeprecationWarning, match="remove_tunnel is deprecated"):
result = devbox.net.remove_tunnel(
- port=8080,
extra_headers={"X-Custom": "value"},
extra_query={"param": "value"},
extra_body={"key": "value"},
@@ -298,7 +297,6 @@ def test_remove_tunnel(self, mock_client: Mock) -> None:
assert result is not None # Verify return value is propagated
mock_client.devboxes.remove_tunnel.assert_called_once_with(
"dbx_123",
- port=8080,
extra_headers={"X-Custom": "value"},
extra_query={"param": "value"},
extra_body={"key": "value"},
diff --git a/tests/test_utils/test_path.py b/tests/test_utils/test_path.py
new file mode 100644
index 000000000..f69d655a1
--- /dev/null
+++ b/tests/test_utils/test_path.py
@@ -0,0 +1,89 @@
+from __future__ import annotations
+
+from typing import Any
+
+import pytest
+
+from runloop_api_client._utils._path import path_template
+
+
+@pytest.mark.parametrize(
+ "template, kwargs, expected",
+ [
+ ("/v1/{id}", dict(id="abc"), "/v1/abc"),
+ ("/v1/{a}/{b}", dict(a="x", b="y"), "/v1/x/y"),
+ ("/v1/{a}{b}/path/{c}?val={d}#{e}", dict(a="x", b="y", c="z", d="u", e="v"), "/v1/xy/path/z?val=u#v"),
+ ("/{w}/{w}", dict(w="echo"), "/echo/echo"),
+ ("/v1/static", {}, "/v1/static"),
+ ("", {}, ""),
+ ("/v1/?q={n}&count=10", dict(n=42), "/v1/?q=42&count=10"),
+ ("/v1/{v}", dict(v=None), "/v1/null"),
+ ("/v1/{v}", dict(v=True), "/v1/true"),
+ ("/v1/{v}", dict(v=False), "/v1/false"),
+ ("/v1/{v}", dict(v=".hidden"), "/v1/.hidden"), # dot prefix ok
+ ("/v1/{v}", dict(v="file.txt"), "/v1/file.txt"), # dot in middle ok
+ ("/v1/{v}", dict(v="..."), "/v1/..."), # triple dot ok
+ ("/v1/{a}{b}", dict(a=".", b="txt"), "/v1/.txt"), # dot var combining with adjacent to be ok
+ ("/items?q={v}#{f}", dict(v=".", f=".."), "/items?q=.#.."), # dots in query/fragment are fine
+ (
+ "/v1/{a}?query={b}",
+ dict(a="../../other/endpoint", b="a&bad=true"),
+ "/v1/..%2F..%2Fother%2Fendpoint?query=a%26bad%3Dtrue",
+ ),
+ ("/v1/{val}", dict(val="a/b/c"), "/v1/a%2Fb%2Fc"),
+ ("/v1/{val}", dict(val="a/b/c?query=value"), "/v1/a%2Fb%2Fc%3Fquery=value"),
+ ("/v1/{val}", dict(val="a/b/c?query=value&bad=true"), "/v1/a%2Fb%2Fc%3Fquery=value&bad=true"),
+ ("/v1/{val}", dict(val="%20"), "/v1/%2520"), # escapes escape sequences in input
+ # Query: slash and ? are safe, # is not
+ ("/items?q={v}", dict(v="a/b"), "/items?q=a/b"),
+ ("/items?q={v}", dict(v="a?b"), "/items?q=a?b"),
+ ("/items?q={v}", dict(v="a#b"), "/items?q=a%23b"),
+ ("/items?q={v}", dict(v="a b"), "/items?q=a%20b"),
+ # Fragment: slash and ? are safe
+ ("/docs#{v}", dict(v="a/b"), "/docs#a/b"),
+ ("/docs#{v}", dict(v="a?b"), "/docs#a?b"),
+ # Path: slash, ? and # are all encoded
+ ("/v1/{v}", dict(v="a/b"), "/v1/a%2Fb"),
+ ("/v1/{v}", dict(v="a?b"), "/v1/a%3Fb"),
+ ("/v1/{v}", dict(v="a#b"), "/v1/a%23b"),
+ # same var encoded differently by component
+ (
+ "/v1/{v}?q={v}#{v}",
+ dict(v="a/b?c#d"),
+ "/v1/a%2Fb%3Fc%23d?q=a/b?c%23d#a/b?c%23d",
+ ),
+ ("/v1/{val}", dict(val="x?admin=true"), "/v1/x%3Fadmin=true"), # query injection
+ ("/v1/{val}", dict(val="x#admin"), "/v1/x%23admin"), # fragment injection
+ ],
+)
+def test_interpolation(template: str, kwargs: dict[str, Any], expected: str) -> None:
+ assert path_template(template, **kwargs) == expected
+
+
+def test_missing_kwarg_raises_key_error() -> None:
+ with pytest.raises(KeyError, match="org_id"):
+ path_template("/v1/{org_id}")
+
+
+@pytest.mark.parametrize(
+ "template, kwargs",
+ [
+ ("{a}/path", dict(a=".")),
+ ("{a}/path", dict(a="..")),
+ ("/v1/{a}", dict(a=".")),
+ ("/v1/{a}", dict(a="..")),
+ ("/v1/{a}/path", dict(a=".")),
+ ("/v1/{a}/path", dict(a="..")),
+ ("/v1/{a}{b}", dict(a=".", b=".")), # adjacent vars → ".."
+ ("/v1/{a}.", dict(a=".")), # var + static → ".."
+ ("/v1/{a}{b}", dict(a="", b=".")), # empty + dot → "."
+ ("/v1/%2e/{x}", dict(x="ok")), # encoded dot in static text
+ ("/v1/%2e./{x}", dict(x="ok")), # mixed encoded ".." in static
+ ("/v1/.%2E/{x}", dict(x="ok")), # mixed encoded ".." in static
+ ("/v1/{v}?q=1", dict(v="..")),
+ ("/v1/{v}#frag", dict(v="..")),
+ ],
+)
+def test_dot_segment_rejected(template: str, kwargs: dict[str, Any]) -> None:
+ with pytest.raises(ValueError, match="dot-segment"):
+ path_template(template, **kwargs)