diff --git a/.stats.yml b/.stats.yml
index 31759036f..311ea3267 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 44
+configured_endpoints: 46
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-15f23a9e2e014d2e5d4d72c39ee31c5556060fb37d1490f308ecce5aeb41d5c8.yml
diff --git a/api.md b/api.md
index 00eb5ac7e..be9c20e21 100644
--- a/api.md
+++ b/api.md
@@ -168,8 +168,10 @@ Methods:
Methods:
+- client.devboxes.executions.retrieve(execution_id, \*, devbox_id, \*\*params) -> DevboxAsyncExecutionDetailView
- client.devboxes.executions.execute_async(id, \*\*params) -> DevboxAsyncExecutionDetailView
- client.devboxes.executions.execute_sync(id, \*\*params) -> DevboxExecutionDetailView
+- client.devboxes.executions.kill(execution_id, \*, devbox_id) -> DevboxAsyncExecutionDetailView
# Repositories
diff --git a/src/runloop_api_client/resources/devboxes/executions.py b/src/runloop_api_client/resources/devboxes/executions.py
index b8cc6fbf3..6d8184e0a 100755
--- a/src/runloop_api_client/resources/devboxes/executions.py
+++ b/src/runloop_api_client/resources/devboxes/executions.py
@@ -20,7 +20,7 @@
async_to_streamed_response_wrapper,
)
from ..._base_client import make_request_options
-from ...types.devboxes import execution_execute_sync_params, execution_execute_async_params
+from ...types.devboxes import execution_retrieve_params, execution_execute_sync_params, execution_execute_async_params
from ...types.devbox_execution_detail_view import DevboxExecutionDetailView
from ...types.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView
@@ -47,6 +47,50 @@ def with_streaming_response(self) -> ExecutionsResourceWithStreamingResponse:
"""
return ExecutionsResourceWithStreamingResponse(self)
+ def retrieve(
+ self,
+ execution_id: str,
+ *,
+ devbox_id: str,
+ last_n: str | NotGiven = NOT_GIVEN,
+ # 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,
+ ) -> DevboxAsyncExecutionDetailView:
+ """
+ Get the latest status of a previously launched asynchronous execuction including
+ stdout/error and the exit code if complete.
+
+ Args:
+ last_n: Last n lines of standard error / standard out to return
+
+ 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 devbox_id:
+ raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}")
+ 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}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"last_n": last_n}, execution_retrieve_params.ExecutionRetrieveParams),
+ ),
+ cast_to=DevboxAsyncExecutionDetailView,
+ )
+
def execute_async(
self,
id: str,
@@ -165,6 +209,50 @@ def execute_sync(
cast_to=DevboxExecutionDetailView,
)
+ def kill(
+ self,
+ execution_id: str,
+ *,
+ devbox_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,
+ idempotency_key: str | None = None,
+ ) -> DevboxAsyncExecutionDetailView:
+ """
+ Kill a previously launched asynchronous execution if it is still running by
+ killing the launched process.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not devbox_id:
+ raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}")
+ 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",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=DevboxAsyncExecutionDetailView,
+ )
+
class AsyncExecutionsResource(AsyncAPIResource):
@cached_property
@@ -186,6 +274,52 @@ def with_streaming_response(self) -> AsyncExecutionsResourceWithStreamingRespons
"""
return AsyncExecutionsResourceWithStreamingResponse(self)
+ async def retrieve(
+ self,
+ execution_id: str,
+ *,
+ devbox_id: str,
+ last_n: str | NotGiven = NOT_GIVEN,
+ # 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,
+ ) -> DevboxAsyncExecutionDetailView:
+ """
+ Get the latest status of a previously launched asynchronous execuction including
+ stdout/error and the exit code if complete.
+
+ Args:
+ last_n: Last n lines of standard error / standard out to return
+
+ 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 devbox_id:
+ raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}")
+ 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}",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"last_n": last_n}, execution_retrieve_params.ExecutionRetrieveParams
+ ),
+ ),
+ cast_to=DevboxAsyncExecutionDetailView,
+ )
+
async def execute_async(
self,
id: str,
@@ -304,50 +438,118 @@ async def execute_sync(
cast_to=DevboxExecutionDetailView,
)
+ async def kill(
+ self,
+ execution_id: str,
+ *,
+ devbox_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,
+ idempotency_key: str | None = None,
+ ) -> DevboxAsyncExecutionDetailView:
+ """
+ Kill a previously launched asynchronous execution if it is still running by
+ killing the launched process.
+
+ 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
+
+ idempotency_key: Specify a custom idempotency key for this request
+ """
+ if not devbox_id:
+ raise ValueError(f"Expected a non-empty value for `devbox_id` but received {devbox_id!r}")
+ 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",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ idempotency_key=idempotency_key,
+ ),
+ cast_to=DevboxAsyncExecutionDetailView,
+ )
+
class ExecutionsResourceWithRawResponse:
def __init__(self, executions: ExecutionsResource) -> None:
self._executions = executions
+ self.retrieve = to_raw_response_wrapper(
+ executions.retrieve,
+ )
self.execute_async = to_raw_response_wrapper(
executions.execute_async,
)
self.execute_sync = to_raw_response_wrapper(
executions.execute_sync,
)
+ self.kill = to_raw_response_wrapper(
+ executions.kill,
+ )
class AsyncExecutionsResourceWithRawResponse:
def __init__(self, executions: AsyncExecutionsResource) -> None:
self._executions = executions
+ self.retrieve = async_to_raw_response_wrapper(
+ executions.retrieve,
+ )
self.execute_async = async_to_raw_response_wrapper(
executions.execute_async,
)
self.execute_sync = async_to_raw_response_wrapper(
executions.execute_sync,
)
+ self.kill = async_to_raw_response_wrapper(
+ executions.kill,
+ )
class ExecutionsResourceWithStreamingResponse:
def __init__(self, executions: ExecutionsResource) -> None:
self._executions = executions
+ self.retrieve = to_streamed_response_wrapper(
+ executions.retrieve,
+ )
self.execute_async = to_streamed_response_wrapper(
executions.execute_async,
)
self.execute_sync = to_streamed_response_wrapper(
executions.execute_sync,
)
+ self.kill = to_streamed_response_wrapper(
+ executions.kill,
+ )
class AsyncExecutionsResourceWithStreamingResponse:
def __init__(self, executions: AsyncExecutionsResource) -> None:
self._executions = executions
+ self.retrieve = async_to_streamed_response_wrapper(
+ executions.retrieve,
+ )
self.execute_async = async_to_streamed_response_wrapper(
executions.execute_async,
)
self.execute_sync = async_to_streamed_response_wrapper(
executions.execute_sync,
)
+ self.kill = async_to_streamed_response_wrapper(
+ executions.kill,
+ )
diff --git a/src/runloop_api_client/types/devboxes/__init__.py b/src/runloop_api_client/types/devboxes/__init__.py
index f2f7c0765..30d13b0fb 100644
--- a/src/runloop_api_client/types/devboxes/__init__.py
+++ b/src/runloop_api_client/types/devboxes/__init__.py
@@ -52,6 +52,7 @@
from .code_action_trigger_kind import CodeActionTriggerKind as CodeActionTriggerKind
from .base_workspace_edit_param import BaseWorkspaceEditParam as BaseWorkspaceEditParam
from .code_action_context_param import CodeActionContextParam as CodeActionContextParam
+from .execution_retrieve_params import ExecutionRetrieveParams as ExecutionRetrieveParams
from .base_parameter_information import BaseParameterInformation as BaseParameterInformation
from .code_segment_info_response import CodeSegmentInfoResponse as CodeSegmentInfoResponse
from .lsp_file_definition_params import LspFileDefinitionParams as LspFileDefinitionParams
diff --git a/src/runloop_api_client/types/devboxes/execution_retrieve_params.py b/src/runloop_api_client/types/devboxes/execution_retrieve_params.py
new file mode 100644
index 000000000..96e8bc24b
--- /dev/null
+++ b/src/runloop_api_client/types/devboxes/execution_retrieve_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, TypedDict
+
+__all__ = ["ExecutionRetrieveParams"]
+
+
+class ExecutionRetrieveParams(TypedDict, total=False):
+ devbox_id: Required[str]
+
+ last_n: str
+ """Last n lines of standard error / standard out to return"""
diff --git a/tests/api_resources/devboxes/test_executions.py b/tests/api_resources/devboxes/test_executions.py
index 0b17d6067..a1a7b8b58 100755
--- a/tests/api_resources/devboxes/test_executions.py
+++ b/tests/api_resources/devboxes/test_executions.py
@@ -17,6 +17,63 @@
class TestExecutions:
parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+ @parametrize
+ def test_method_retrieve(self, client: Runloop) -> None:
+ execution = client.devboxes.executions.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: Runloop) -> None:
+ execution = client.devboxes.executions.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ last_n="last_n",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: Runloop) -> None:
+ response = client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: Runloop) -> None:
+ with client.devboxes.executions.with_streaming_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, 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 `devbox_id` but received ''"):
+ client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="",
+ devbox_id="devbox_id",
+ )
+
@parametrize
def test_method_execute_async(self, client: Runloop) -> None:
execution = client.devboxes.executions.execute_async(
@@ -119,10 +176,115 @@ def test_path_params_execute_sync(self, client: Runloop) -> None:
command="command",
)
+ @parametrize
+ def test_method_kill(self, client: Runloop) -> None:
+ execution = client.devboxes.executions.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ def test_raw_response_kill(self, client: Runloop) -> None:
+ response = client.devboxes.executions.with_raw_response.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ def test_streaming_response_kill(self, client: Runloop) -> None:
+ with client.devboxes.executions.with_streaming_response.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_kill(self, client: Runloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"):
+ client.devboxes.executions.with_raw_response.kill(
+ execution_id="execution_id",
+ devbox_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ client.devboxes.executions.with_raw_response.kill(
+ execution_id="",
+ devbox_id="devbox_id",
+ )
+
class TestAsyncExecutions:
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncRunloop) -> None:
+ execution = await async_client.devboxes.executions.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncRunloop) -> None:
+ execution = await async_client.devboxes.executions.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ last_n="last_n",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncRunloop) -> None:
+ async with async_client.devboxes.executions.with_streaming_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, 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 `devbox_id` but received ''"):
+ await async_client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="execution_id",
+ devbox_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.devboxes.executions.with_raw_response.retrieve(
+ execution_id="",
+ devbox_id="devbox_id",
+ )
+
@parametrize
async def test_method_execute_async(self, async_client: AsyncRunloop) -> None:
execution = await async_client.devboxes.executions.execute_async(
@@ -224,3 +386,51 @@ async def test_path_params_execute_sync(self, async_client: AsyncRunloop) -> Non
id="",
command="command",
)
+
+ @parametrize
+ async def test_method_kill(self, async_client: AsyncRunloop) -> None:
+ execution = await async_client.devboxes.executions.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ async def test_raw_response_kill(self, async_client: AsyncRunloop) -> None:
+ response = await async_client.devboxes.executions.with_raw_response.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ execution = await response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_kill(self, async_client: AsyncRunloop) -> None:
+ async with async_client.devboxes.executions.with_streaming_response.kill(
+ execution_id="execution_id",
+ devbox_id="devbox_id",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ execution = await response.parse()
+ assert_matches_type(DevboxAsyncExecutionDetailView, execution, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_kill(self, async_client: AsyncRunloop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `devbox_id` but received ''"):
+ await async_client.devboxes.executions.with_raw_response.kill(
+ execution_id="execution_id",
+ devbox_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `execution_id` but received ''"):
+ await async_client.devboxes.executions.with_raw_response.kill(
+ execution_id="",
+ devbox_id="devbox_id",
+ )