Skip to content

Commit 016bb0e

Browse files
release: 1.4.0 (#728)
Co-authored-by: stainless-app[bot] <142633134+stainless-app[bot]@users.noreply.github.com> Co-authored-by: Albert Li <[email protected]>
1 parent 3f3da5e commit 016bb0e

30 files changed

+1944
-164
lines changed

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "1.3.2"
2+
".": "1.4.0"
33
}

.stats.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 106
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-63dab7833d6670810c4f4882df560ebbfe2de8e8e1a98d51422368607b5335ae.yml
3-
openapi_spec_hash: ebb5068064f7469f9239b18a51a6fe44
4-
config_hash: fd168de77f219e46a1427bbec2eecfb9
1+
configured_endpoints: 111
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-84e997ca5716b9378a58a1bdf3d6616cf3be80156a6aaed1bed469fe93ba2c95.yml
3+
openapi_spec_hash: b44a4ba1c2c3cb775c14545f2bab05a8
4+
config_hash: 22f65246be4646c23dde9f69f51252e7

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## 1.4.0 (2026-01-30)
4+
5+
Full Changelog: [v1.3.2...v1.4.0](https://github.com/runloopai/api-client-python/compare/v1.3.2...v1.4.0)
6+
7+
### Features
8+
9+
* **client:** add custom JSON encoder for extended type support ([840addd](https://github.com/runloopai/api-client-python/commit/840addd8884fd93ede0c9bbc2a16cf399d6372d0))
10+
* **devbox:** add gateway routes ([#7212](https://github.com/runloopai/api-client-python/issues/7212)) ([2527bb7](https://github.com/runloopai/api-client-python/commit/2527bb7714f9ce9114964286bfbb35582ceaa976))
11+
* **devbox:** add new tunnel APIs and deprecate old tunnel API ([#7227](https://github.com/runloopai/api-client-python/issues/7227)) ([71620a1](https://github.com/runloopai/api-client-python/commit/71620a114080506898864b6d73378d4ff30b1070))
12+
13+
14+
### Chores
15+
16+
* **devbox:** deprecate remove tunnel API ([#7230](https://github.com/runloopai/api-client-python/issues/7230)) ([d48832d](https://github.com/runloopai/api-client-python/commit/d48832d0aa076bd621decae3f5dadca7141c29d3))
17+
* **documentation:** made warning message language more accurate ([#7215](https://github.com/runloopai/api-client-python/issues/7215)) ([08e0586](https://github.com/runloopai/api-client-python/commit/08e058660cf02e67701899e3b46173c5e9011b7d))
18+
319
## 1.3.2 (2026-01-30)
420

521
Full Changelog: [v1.3.1...v1.3.2](https://github.com/runloopai/api-client-python/compare/v1.3.1...v1.3.2)

api.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,24 @@ Methods:
397397
- <code title="post /v1/network-policies/{id}">client.network_policies.<a href="./src/runloop_api_client/resources/network_policies.py">update</a>(id, \*\*<a href="src/runloop_api_client/types/network_policy_update_params.py">params</a>) -> <a href="./src/runloop_api_client/types/network_policy_view.py">NetworkPolicyView</a></code>
398398
- <code title="get /v1/network-policies">client.network_policies.<a href="./src/runloop_api_client/resources/network_policies.py">list</a>(\*\*<a href="src/runloop_api_client/types/network_policy_list_params.py">params</a>) -> <a href="./src/runloop_api_client/types/network_policy_view.py">SyncNetworkPoliciesCursorIDPage[NetworkPolicyView]</a></code>
399399
- <code title="post /v1/network-policies/{id}/delete">client.network_policies.<a href="./src/runloop_api_client/resources/network_policies.py">delete</a>(id) -> <a href="./src/runloop_api_client/types/network_policy_view.py">NetworkPolicyView</a></code>
400+
401+
# GatewayConfigs
402+
403+
Types:
404+
405+
```python
406+
from runloop_api_client.types import (
407+
GatewayConfigCreateParameters,
408+
GatewayConfigListView,
409+
GatewayConfigUpdateParameters,
410+
GatewayConfigView,
411+
)
412+
```
413+
414+
Methods:
415+
416+
- <code title="post /v1/gateway-configs">client.gateway_configs.<a href="./src/runloop_api_client/resources/gateway_configs.py">create</a>(\*\*<a href="src/runloop_api_client/types/gateway_config_create_params.py">params</a>) -> <a href="./src/runloop_api_client/types/gateway_config_view.py">GatewayConfigView</a></code>
417+
- <code title="get /v1/gateway-configs/{id}">client.gateway_configs.<a href="./src/runloop_api_client/resources/gateway_configs.py">retrieve</a>(id) -> <a href="./src/runloop_api_client/types/gateway_config_view.py">GatewayConfigView</a></code>
418+
- <code title="post /v1/gateway-configs/{id}">client.gateway_configs.<a href="./src/runloop_api_client/resources/gateway_configs.py">update</a>(id, \*\*<a href="src/runloop_api_client/types/gateway_config_update_params.py">params</a>) -> <a href="./src/runloop_api_client/types/gateway_config_view.py">GatewayConfigView</a></code>
419+
- <code title="get /v1/gateway-configs">client.gateway_configs.<a href="./src/runloop_api_client/resources/gateway_configs.py">list</a>(\*\*<a href="src/runloop_api_client/types/gateway_config_list_params.py">params</a>) -> <a href="./src/runloop_api_client/types/gateway_config_view.py">SyncGatewayConfigsCursorIDPage[GatewayConfigView]</a></code>
420+
- <code title="post /v1/gateway-configs/{id}/delete">client.gateway_configs.<a href="./src/runloop_api_client/resources/gateway_configs.py">delete</a>(id) -> <a href="./src/runloop_api_client/types/gateway_config_view.py">GatewayConfigView</a></code>

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "runloop_api_client"
3-
version = "1.3.2"
3+
version = "1.4.0"
44
description = "The official Python library for the runloop API"
55
dynamic = ["readme"]
66
license = "MIT"

src/runloop_api_client/_base_client.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
APIConnectionError,
8787
APIResponseValidationError,
8888
)
89+
from ._utils._json import openapi_dumps
8990

9091
log: logging.Logger = logging.getLogger(__name__)
9192

@@ -554,8 +555,10 @@ def _build_request(
554555
kwargs["content"] = options.content
555556
elif isinstance(json_data, bytes):
556557
kwargs["content"] = json_data
557-
else:
558-
kwargs["json"] = json_data if is_given(json_data) else None
558+
elif not files:
559+
# Don't set content when JSON is sent as multipart/form-data,
560+
# since httpx's content param overrides other body arguments
561+
kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None
559562
kwargs["files"] = files
560563
else:
561564
headers.pop("Content-Type", None)

src/runloop_api_client/_client.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
repositories,
4343
benchmark_jobs,
4444
benchmark_runs,
45+
gateway_configs,
4546
network_policies,
4647
)
4748
from .resources.agents import AgentsResource, AsyncAgentsResource
@@ -52,6 +53,7 @@
5253
from .resources.repositories import RepositoriesResource, AsyncRepositoriesResource
5354
from .resources.benchmark_jobs import BenchmarkJobsResource, AsyncBenchmarkJobsResource
5455
from .resources.benchmark_runs import BenchmarkRunsResource, AsyncBenchmarkRunsResource
56+
from .resources.gateway_configs import GatewayConfigsResource, AsyncGatewayConfigsResource
5557
from .resources.network_policies import NetworkPoliciesResource, AsyncNetworkPoliciesResource
5658
from .resources.devboxes.devboxes import DevboxesResource, AsyncDevboxesResource
5759
from .resources.scenarios.scenarios import ScenariosResource, AsyncScenariosResource
@@ -182,6 +184,12 @@ def network_policies(self) -> NetworkPoliciesResource:
182184

183185
return NetworkPoliciesResource(self)
184186

187+
@cached_property
188+
def gateway_configs(self) -> GatewayConfigsResource:
189+
from .resources.gateway_configs import GatewayConfigsResource
190+
191+
return GatewayConfigsResource(self)
192+
185193
@cached_property
186194
def with_raw_response(self) -> RunloopWithRawResponse:
187195
return RunloopWithRawResponse(self)
@@ -418,6 +426,12 @@ def network_policies(self) -> AsyncNetworkPoliciesResource:
418426

419427
return AsyncNetworkPoliciesResource(self)
420428

429+
@cached_property
430+
def gateway_configs(self) -> AsyncGatewayConfigsResource:
431+
from .resources.gateway_configs import AsyncGatewayConfigsResource
432+
433+
return AsyncGatewayConfigsResource(self)
434+
421435
@cached_property
422436
def with_raw_response(self) -> AsyncRunloopWithRawResponse:
423437
return AsyncRunloopWithRawResponse(self)
@@ -603,6 +617,12 @@ def network_policies(self) -> network_policies.NetworkPoliciesResourceWithRawRes
603617

604618
return NetworkPoliciesResourceWithRawResponse(self._client.network_policies)
605619

620+
@cached_property
621+
def gateway_configs(self) -> gateway_configs.GatewayConfigsResourceWithRawResponse:
622+
from .resources.gateway_configs import GatewayConfigsResourceWithRawResponse
623+
624+
return GatewayConfigsResourceWithRawResponse(self._client.gateway_configs)
625+
606626

607627
class AsyncRunloopWithRawResponse:
608628
_client: AsyncRunloop
@@ -676,6 +696,12 @@ def network_policies(self) -> network_policies.AsyncNetworkPoliciesResourceWithR
676696

677697
return AsyncNetworkPoliciesResourceWithRawResponse(self._client.network_policies)
678698

699+
@cached_property
700+
def gateway_configs(self) -> gateway_configs.AsyncGatewayConfigsResourceWithRawResponse:
701+
from .resources.gateway_configs import AsyncGatewayConfigsResourceWithRawResponse
702+
703+
return AsyncGatewayConfigsResourceWithRawResponse(self._client.gateway_configs)
704+
679705

680706
class RunloopWithStreamedResponse:
681707
_client: Runloop
@@ -749,6 +775,12 @@ def network_policies(self) -> network_policies.NetworkPoliciesResourceWithStream
749775

750776
return NetworkPoliciesResourceWithStreamingResponse(self._client.network_policies)
751777

778+
@cached_property
779+
def gateway_configs(self) -> gateway_configs.GatewayConfigsResourceWithStreamingResponse:
780+
from .resources.gateway_configs import GatewayConfigsResourceWithStreamingResponse
781+
782+
return GatewayConfigsResourceWithStreamingResponse(self._client.gateway_configs)
783+
752784

753785
class AsyncRunloopWithStreamedResponse:
754786
_client: AsyncRunloop
@@ -822,6 +854,12 @@ def network_policies(self) -> network_policies.AsyncNetworkPoliciesResourceWithS
822854

823855
return AsyncNetworkPoliciesResourceWithStreamingResponse(self._client.network_policies)
824856

857+
@cached_property
858+
def gateway_configs(self) -> gateway_configs.AsyncGatewayConfigsResourceWithStreamingResponse:
859+
from .resources.gateway_configs import AsyncGatewayConfigsResourceWithStreamingResponse
860+
861+
return AsyncGatewayConfigsResourceWithStreamingResponse(self._client.gateway_configs)
862+
825863

826864
Client = Runloop
827865

src/runloop_api_client/_compat.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def model_dump(
139139
exclude_defaults: bool = False,
140140
warnings: bool = True,
141141
mode: Literal["json", "python"] = "python",
142+
by_alias: bool | None = None,
142143
) -> dict[str, Any]:
143144
if (not PYDANTIC_V1) or hasattr(model, "model_dump"):
144145
return model.model_dump(
@@ -148,13 +149,12 @@ def model_dump(
148149
exclude_defaults=exclude_defaults,
149150
# warnings are not supported in Pydantic v1
150151
warnings=True if PYDANTIC_V1 else warnings,
152+
by_alias=by_alias,
151153
)
152154
return cast(
153155
"dict[str, Any]",
154156
model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast]
155-
exclude=exclude,
156-
exclude_unset=exclude_unset,
157-
exclude_defaults=exclude_defaults,
157+
exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias)
158158
),
159159
)
160160

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import json
2+
from typing import Any
3+
from datetime import datetime
4+
from typing_extensions import override
5+
6+
import pydantic
7+
8+
from .._compat import model_dump
9+
10+
11+
def openapi_dumps(obj: Any) -> bytes:
12+
"""
13+
Serialize an object to UTF-8 encoded JSON bytes.
14+
15+
Extends the standard json.dumps with support for additional types
16+
commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc.
17+
"""
18+
return json.dumps(
19+
obj,
20+
cls=_CustomEncoder,
21+
# Uses the same defaults as httpx's JSON serialization
22+
ensure_ascii=False,
23+
separators=(",", ":"),
24+
allow_nan=False,
25+
).encode()
26+
27+
28+
class _CustomEncoder(json.JSONEncoder):
29+
@override
30+
def default(self, o: Any) -> Any:
31+
if isinstance(o, datetime):
32+
return o.isoformat()
33+
if isinstance(o, pydantic.BaseModel):
34+
return model_dump(o, exclude_unset=True, mode="json", by_alias=True)
35+
return super().default(o)

src/runloop_api_client/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "runloop_api_client"
4-
__version__ = "1.3.2" # x-release-please-version
4+
__version__ = "1.4.0" # x-release-please-version

0 commit comments

Comments
 (0)