Skip to content

Commit 2527bb7

Browse files
feat(devbox): add gateway routes (#7212)
1 parent 840addd commit 2527bb7

17 files changed

+1496
-7
lines changed

.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-294ebcf6886a5ddbebeaa70923b7674757459e73ef08cd2fbc63fb70e1932eac.yml
3+
openapi_spec_hash: 3a2a14e7ddd646f53d9f21bef2e84ec5
4+
config_hash: 22f65246be4646c23dde9f69f51252e7

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>

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/pagination.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
"AsyncObjectsCursorIDPage",
3131
"SyncNetworkPoliciesCursorIDPage",
3232
"AsyncNetworkPoliciesCursorIDPage",
33+
"SyncGatewayConfigsCursorIDPage",
34+
"AsyncGatewayConfigsCursorIDPage",
3335
]
3436

3537
_T = TypeVar("_T")
@@ -95,6 +97,11 @@ class NetworkPoliciesCursorIDPageItem(Protocol):
9597
id: str
9698

9799

100+
@runtime_checkable
101+
class GatewayConfigsCursorIDPageItem(Protocol):
102+
id: str
103+
104+
98105
class SyncBlueprintsCursorIDPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
99106
blueprints: List[_T]
100107
has_more: Optional[bool] = None
@@ -909,3 +916,71 @@ def next_page_info(self) -> Optional[PageInfo]:
909916
return None
910917

911918
return PageInfo(params={"starting_after": item.id})
919+
920+
921+
class SyncGatewayConfigsCursorIDPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]):
922+
gateway_configs: List[_T]
923+
has_more: Optional[bool] = None
924+
total_count: Optional[int] = None
925+
926+
@override
927+
def _get_page_items(self) -> List[_T]:
928+
gateway_configs = self.gateway_configs
929+
if not gateway_configs:
930+
return []
931+
return gateway_configs
932+
933+
@override
934+
def has_next_page(self) -> bool:
935+
has_more = self.has_more
936+
if has_more is not None and has_more is False:
937+
return False
938+
939+
return super().has_next_page()
940+
941+
@override
942+
def next_page_info(self) -> Optional[PageInfo]:
943+
gateway_configs = self.gateway_configs
944+
if not gateway_configs:
945+
return None
946+
947+
item = cast(Any, gateway_configs[-1])
948+
if not isinstance(item, GatewayConfigsCursorIDPageItem) or item.id is None: # pyright: ignore[reportUnnecessaryComparison]
949+
# TODO emit warning log
950+
return None
951+
952+
return PageInfo(params={"starting_after": item.id})
953+
954+
955+
class AsyncGatewayConfigsCursorIDPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]):
956+
gateway_configs: List[_T]
957+
has_more: Optional[bool] = None
958+
total_count: Optional[int] = None
959+
960+
@override
961+
def _get_page_items(self) -> List[_T]:
962+
gateway_configs = self.gateway_configs
963+
if not gateway_configs:
964+
return []
965+
return gateway_configs
966+
967+
@override
968+
def has_next_page(self) -> bool:
969+
has_more = self.has_more
970+
if has_more is not None and has_more is False:
971+
return False
972+
973+
return super().has_next_page()
974+
975+
@override
976+
def next_page_info(self) -> Optional[PageInfo]:
977+
gateway_configs = self.gateway_configs
978+
if not gateway_configs:
979+
return None
980+
981+
item = cast(Any, gateway_configs[-1])
982+
if not isinstance(item, GatewayConfigsCursorIDPageItem) or item.id is None: # pyright: ignore[reportUnnecessaryComparison]
983+
# TODO emit warning log
984+
return None
985+
986+
return PageInfo(params={"starting_after": item.id})

src/runloop_api_client/resources/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@
8080
BenchmarkRunsResourceWithStreamingResponse,
8181
AsyncBenchmarkRunsResourceWithStreamingResponse,
8282
)
83+
from .gateway_configs import (
84+
GatewayConfigsResource,
85+
AsyncGatewayConfigsResource,
86+
GatewayConfigsResourceWithRawResponse,
87+
AsyncGatewayConfigsResourceWithRawResponse,
88+
GatewayConfigsResourceWithStreamingResponse,
89+
AsyncGatewayConfigsResourceWithStreamingResponse,
90+
)
8391
from .network_policies import (
8492
NetworkPoliciesResource,
8593
AsyncNetworkPoliciesResource,
@@ -156,4 +164,10 @@
156164
"AsyncNetworkPoliciesResourceWithRawResponse",
157165
"NetworkPoliciesResourceWithStreamingResponse",
158166
"AsyncNetworkPoliciesResourceWithStreamingResponse",
167+
"GatewayConfigsResource",
168+
"AsyncGatewayConfigsResource",
169+
"GatewayConfigsResourceWithRawResponse",
170+
"AsyncGatewayConfigsResourceWithRawResponse",
171+
"GatewayConfigsResourceWithStreamingResponse",
172+
"AsyncGatewayConfigsResourceWithStreamingResponse",
159173
]

src/runloop_api_client/resources/devboxes/devboxes.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ def create(
185185
entrypoint: Optional[str] | Omit = omit,
186186
environment_variables: Optional[Dict[str, str]] | Omit = omit,
187187
file_mounts: Optional[Dict[str, str]] | Omit = omit,
188+
gateways: Optional[Dict[str, devbox_create_params.Gateways]] | Omit = omit,
188189
launch_parameters: Optional[LaunchParameters] | Omit = omit,
189190
metadata: Optional[Dict[str, str]] | Omit = omit,
190191
mounts: Optional[Iterable[Mount]] | Omit = omit,
@@ -227,6 +228,12 @@ def create(
227228
228229
file_mounts: Map of paths and file contents to write before setup. Use mounts instead.
229230
231+
gateways: [Beta] (Optional) Gateway specifications for credential proxying. Map key is the
232+
environment variable prefix (e.g., 'GWS_ANTHROPIC'). The gateway will proxy
233+
requests to external APIs using the specified credential without exposing the
234+
real API key. Example: {'GWS_ANTHROPIC': {'gateway': 'anthropic', 'secret':
235+
'my_claude_key'}}
236+
230237
launch_parameters: Parameters to configure the resources and launch time behavior of the Devbox.
231238
232239
metadata: User defined metadata to attach to the devbox for organization.
@@ -265,6 +272,7 @@ def create(
265272
"entrypoint": entrypoint,
266273
"environment_variables": environment_variables,
267274
"file_mounts": file_mounts,
275+
"gateways": gateways,
268276
"launch_parameters": launch_parameters,
269277
"metadata": metadata,
270278
"mounts": mounts,
@@ -1723,6 +1731,7 @@ async def create(
17231731
entrypoint: Optional[str] | Omit = omit,
17241732
environment_variables: Optional[Dict[str, str]] | Omit = omit,
17251733
file_mounts: Optional[Dict[str, str]] | Omit = omit,
1734+
gateways: Optional[Dict[str, devbox_create_params.Gateways]] | Omit = omit,
17261735
launch_parameters: Optional[LaunchParameters] | Omit = omit,
17271736
metadata: Optional[Dict[str, str]] | Omit = omit,
17281737
mounts: Optional[Iterable[Mount]] | Omit = omit,
@@ -1765,6 +1774,12 @@ async def create(
17651774
17661775
file_mounts: Map of paths and file contents to write before setup. Use mounts instead.
17671776
1777+
gateways: [Beta] (Optional) Gateway specifications for credential proxying. Map key is the
1778+
environment variable prefix (e.g., 'GWS_ANTHROPIC'). The gateway will proxy
1779+
requests to external APIs using the specified credential without exposing the
1780+
real API key. Example: {'GWS_ANTHROPIC': {'gateway': 'anthropic', 'secret':
1781+
'my_claude_key'}}
1782+
17681783
launch_parameters: Parameters to configure the resources and launch time behavior of the Devbox.
17691784
17701785
metadata: User defined metadata to attach to the devbox for organization.
@@ -1803,6 +1818,7 @@ async def create(
18031818
"entrypoint": entrypoint,
18041819
"environment_variables": environment_variables,
18051820
"file_mounts": file_mounts,
1821+
"gateways": gateways,
18061822
"launch_parameters": launch_parameters,
18071823
"metadata": metadata,
18081824
"mounts": mounts,

0 commit comments

Comments
 (0)