diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 2fbefb942..85c311828 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.58.0"
+ ".": "0.59.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 900ce23a3..1eaf9aeec 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 101
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-6b4c63a026f224ec02ccd715e063e07107b545bb859218afaac2b3df84cd227a.yml
-openapi_spec_hash: 76072cd766a9c45cff8890bb2bb8b1d5
-config_hash: a8ac5e38099129b07ae4decb0774719d
+configured_endpoints: 102
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-a8e2289b32b616e0bd7e15995a6553d0335bd21e30617a013d07450f8f5a7a20.yml
+openapi_spec_hash: cd13a7af1ffe64c7ce8753f87786e01f
+config_hash: 457068371129b47b67f0f2d6b8267368
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5095bbba2..7b00c7c10 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog
+## 0.59.0 (2025-09-08)
+
+Full Changelog: [v0.58.0...v0.59.0](https://github.com/runloopai/api-client-python/compare/v0.58.0...v0.59.0)
+
+### Features
+
+* **api:** api update ([d28f600](https://github.com/runloopai/api-client-python/commit/d28f60090e9c8c3c508812bfaf4bacbdd0b64330))
+* **api:** api update ([a7b44bc](https://github.com/runloopai/api-client-python/commit/a7b44bc091060518d507dbd806694de9ba09c1f8))
+* **api:** api update ([39c93bd](https://github.com/runloopai/api-client-python/commit/39c93bd7061e77c01fbb1cd913ede94ce90664c4))
+
+
+### Chores
+
+* **internal:** codegen related update ([4ed8b7a](https://github.com/runloopai/api-client-python/commit/4ed8b7a3ab98378214f74e79202051260f8488da))
+* **tests:** simplify `get_platform` test ([6b38a37](https://github.com/runloopai/api-client-python/commit/6b38a37e0e3630b360090fd4ab91b4ffc431c46c))
+
## 0.58.0 (2025-09-04)
Full Changelog: [v0.57.0...v0.58.0](https://github.com/runloopai/api-client-python/compare/v0.57.0...v0.58.0)
diff --git a/api.md b/api.md
index 0c827fe6b..3076ddf36 100644
--- a/api.md
+++ b/api.md
@@ -73,6 +73,7 @@ Types:
from runloop_api_client.types import (
DevboxAsyncExecutionDetailView,
DevboxExecutionDetailView,
+ DevboxKillExecutionRequest,
DevboxListView,
DevboxSnapshotListView,
DevboxSnapshotView,
@@ -266,7 +267,8 @@ Methods:
- client.devboxes.executions.execute_async(id, \*\*params) -> DevboxAsyncExecutionDetailView
- client.devboxes.executions.execute_sync(id, \*\*params) -> DevboxExecutionDetailView
- client.devboxes.executions.kill(execution_id, \*, devbox_id, \*\*params) -> DevboxAsyncExecutionDetailView
-- client.devboxes.executions.stream_stdout_updates(execution_id, \*, devbox_id, \*\*params) -> DevboxAsyncExecutionDetailView
+- client.devboxes.executions.stream_stderr_updates(execution_id, \*, devbox_id, \*\*params) -> ExecutionUpdateChunk
+- client.devboxes.executions.stream_stdout_updates(execution_id, \*, devbox_id, \*\*params) -> ExecutionUpdateChunk
# Scenarios
diff --git a/mypy.ini b/mypy.ini
deleted file mode 100644
index 0a62aa9d6..000000000
--- a/mypy.ini
+++ /dev/null
@@ -1,50 +0,0 @@
-[mypy]
-pretty = True
-show_error_codes = True
-
-# Exclude _files.py because mypy isn't smart enough to apply
-# the correct type narrowing and as this is an internal module
-# it's fine to just use Pyright.
-#
-# We also exclude our `tests` as mypy doesn't always infer
-# types correctly and Pyright will still catch any type errors.
-exclude = ^(src/runloop_api_client/_files\.py|_dev/.*\.py|tests/.*)$
-
-strict_equality = True
-implicit_reexport = True
-check_untyped_defs = True
-no_implicit_optional = True
-
-warn_return_any = True
-warn_unreachable = True
-warn_unused_configs = True
-
-# Turn these options off as it could cause conflicts
-# with the Pyright options.
-warn_unused_ignores = False
-warn_redundant_casts = False
-
-disallow_any_generics = True
-disallow_untyped_defs = True
-disallow_untyped_calls = True
-disallow_subclassing_any = True
-disallow_incomplete_defs = True
-disallow_untyped_decorators = True
-cache_fine_grained = True
-
-# By default, mypy reports an error if you assign a value to the result
-# of a function call that doesn't return anything. We do this in our test
-# cases:
-# ```
-# result = ...
-# assert result is None
-# ```
-# Changing this codegen to make mypy happy would increase complexity
-# and would not be worth it.
-disable_error_code = func-returns-value,overload-cannot-match
-
-# https://github.com/python/mypy/issues/12162
-[mypy.overrides]
-module = "black.files.*"
-ignore_errors = true
-ignore_missing_imports = true
diff --git a/pyproject.toml b/pyproject.toml
index 52e917e86..3e52c5ea7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
-version = "0.58.0"
+version = "0.59.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
@@ -57,7 +57,6 @@ dev-dependencies = [
"dirty-equals>=0.6.0",
"importlib-metadata>=6.7.0",
"rich>=13.7.1",
- "nest_asyncio==1.6.0",
"pytest-xdist>=3.6.1",
]
@@ -166,6 +165,58 @@ reportOverlappingOverload = false
reportImportCycles = false
reportPrivateUsage = false
+[tool.mypy]
+pretty = true
+show_error_codes = true
+
+# Exclude _files.py because mypy isn't smart enough to apply
+# the correct type narrowing and as this is an internal module
+# it's fine to just use Pyright.
+#
+# We also exclude our `tests` as mypy doesn't always infer
+# types correctly and Pyright will still catch any type errors.
+exclude = ['src/runloop_api_client/_files.py', '_dev/.*.py', 'tests/.*']
+
+strict_equality = true
+implicit_reexport = true
+check_untyped_defs = true
+no_implicit_optional = true
+
+warn_return_any = true
+warn_unreachable = true
+warn_unused_configs = true
+
+# Turn these options off as it could cause conflicts
+# with the Pyright options.
+warn_unused_ignores = false
+warn_redundant_casts = false
+
+disallow_any_generics = true
+disallow_untyped_defs = true
+disallow_untyped_calls = true
+disallow_subclassing_any = true
+disallow_incomplete_defs = true
+disallow_untyped_decorators = true
+cache_fine_grained = true
+
+# By default, mypy reports an error if you assign a value to the result
+# of a function call that doesn't return anything. We do this in our test
+# cases:
+# ```
+# result = ...
+# assert result is None
+# ```
+# Changing this codegen to make mypy happy would increase complexity
+# and would not be worth it.
+disable_error_code = "func-returns-value,overload-cannot-match"
+
+# https://github.com/python/mypy/issues/12162
+[[tool.mypy.overrides]]
+module = "black.files.*"
+ignore_errors = true
+ignore_missing_imports = true
+
+
[tool.ruff]
line-length = 120
output-format = "grouped"
diff --git a/requirements-dev.lock b/requirements-dev.lock
index de857a2d6..2a74d01aa 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -75,7 +75,6 @@ multidict==6.4.4
mypy==1.14.1
mypy-extensions==1.0.0
# via mypy
-nest-asyncio==1.6.0
nodeenv==1.8.0
# via pyright
nox==2023.4.22
diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py
index d2b85015b..533907a8a 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__ = "0.58.0" # x-release-please-version
+__version__ = "0.59.0" # x-release-please-version
diff --git a/src/runloop_api_client/resources/devboxes/executions.py b/src/runloop_api_client/resources/devboxes/executions.py
index 0002113ff..27cd21c79 100755
--- a/src/runloop_api_client/resources/devboxes/executions.py
+++ b/src/runloop_api_client/resources/devboxes/executions.py
@@ -26,7 +26,8 @@
execution_retrieve_params,
execution_execute_sync_params,
execution_execute_async_params,
- execution_stream_updates_params,
+ execution_stream_stderr_updates_params,
+ execution_stream_stdout_updates_params,
)
from ...lib.polling_async import async_poll_until
from ...types.devbox_execution_detail_view import DevboxExecutionDetailView
@@ -299,6 +300,9 @@ def kill(
killing the launched process. Optionally kill the entire process group.
Args:
+ kill_process_group: Whether to kill the entire process group (default: false). If true, kills all
+ processes in the same process group as the target process.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -326,7 +330,7 @@ def kill(
cast_to=DevboxAsyncExecutionDetailView,
)
- def stream_stdout_updates(
+ def stream_stderr_updates(
self,
execution_id: str,
*,
@@ -340,7 +344,7 @@ def stream_stdout_updates(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> Stream[ExecutionUpdateChunk]:
"""
- Tails the stdout logs for the given execution with SSE streaming
+ Tails the stderr logs for the given execution with SSE streaming
Args:
offset: The byte offset to start the stream from
@@ -359,14 +363,14 @@ def stream_stdout_updates(
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
if extra_headers and extra_headers.get(RAW_RESPONSE_HEADER):
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
- {"offset": offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": offset}, execution_stream_stderr_updates_params.ExecutionStreamStderrUpdatesParams
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -377,14 +381,15 @@ 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",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
- {"offset": new_offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": new_offset},
+ execution_stream_stderr_updates_params.ExecutionStreamStderrUpdatesParams,
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -405,7 +410,7 @@ def get_offset(item: ExecutionUpdateChunk) -> str | None:
ReconnectingStream(current_stream=initial_stream, stream_creator=create_stream, get_offset=get_offset),
)
- def stream_stderr_updates(
+ def stream_stdout_updates(
self,
execution_id: str,
*,
@@ -419,7 +424,7 @@ def stream_stderr_updates(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> Stream[ExecutionUpdateChunk]:
"""
- Tails the stderr logs for the given execution with SSE streaming
+ Tails the stdout logs for the given execution with SSE streaming
Args:
offset: The byte offset to start the stream from
@@ -438,14 +443,14 @@ def stream_stderr_updates(
raise ValueError(f"Expected a non-empty value for `execution_id` but received {execution_id!r}")
if extra_headers and extra_headers.get(RAW_RESPONSE_HEADER):
return self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
- {"offset": offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": offset}, execution_stream_stdout_updates_params.ExecutionStreamStdoutUpdatesParams
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -456,14 +461,15 @@ 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",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=maybe_transform(
- {"offset": new_offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": new_offset},
+ execution_stream_stdout_updates_params.ExecutionStreamStdoutUpdatesParams,
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -736,6 +742,9 @@ async def kill(
killing the launched process. Optionally kill the entire process group.
Args:
+ kill_process_group: Whether to kill the entire process group (default: false). If true, kills all
+ processes in the same process group as the target process.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -765,7 +774,7 @@ async def kill(
cast_to=DevboxAsyncExecutionDetailView,
)
- async def stream_updates(
+ async def stream_stderr_updates(
self,
execution_id: str,
*,
@@ -779,7 +788,7 @@ async def stream_updates(
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> AsyncStream[ExecutionUpdateChunk]:
"""
- Tails the logs for the given execution with SSE streaming
+ Tails the stderr logs for the given execution with SSE streaming
Args:
offset: The byte offset to start the stream from
@@ -796,17 +805,16 @@ async def stream_updates(
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}")
- # If caller requested a raw or streaming response wrapper, return the underlying stream as-is
if extra_headers and extra_headers.get(RAW_RESPONSE_HEADER):
return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_updates",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
- {"offset": offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": offset}, execution_stream_stderr_updates_params.ExecutionStreamStderrUpdatesParams
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -817,14 +825,15 @@ async def stream_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_updates",
+ f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
options=make_request_options(
extra_headers=extra_headers,
extra_query=extra_query,
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
- {"offset": new_offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": new_offset},
+ execution_stream_stderr_updates_params.ExecutionStreamStderrUpdatesParams,
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -876,6 +885,7 @@ async def stream_stdout_updates(
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}")
+ # If caller requested a raw or streaming response wrapper, return the underlying stream as-is
if extra_headers and extra_headers.get(RAW_RESPONSE_HEADER):
return await self._get(
f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stdout_updates",
@@ -885,7 +895,7 @@ async def stream_stdout_updates(
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
- {"offset": offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": offset}, execution_stream_stdout_updates_params.ExecutionStreamStdoutUpdatesParams
),
),
cast_to=DevboxAsyncExecutionDetailView,
@@ -903,86 +913,8 @@ async def create_stream(last_offset: str | None) -> AsyncStream[ExecutionUpdateC
extra_body=extra_body,
timeout=timeout,
query=await async_maybe_transform(
- {"offset": new_offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
- ),
- ),
- cast_to=DevboxAsyncExecutionDetailView,
- stream=True,
- stream_cls=AsyncStream[ExecutionUpdateChunk],
- )
-
- initial_stream = await create_stream(None)
-
- def get_offset(item: ExecutionUpdateChunk) -> str | None:
- value = getattr(item, "offset", None)
- if value is None:
- return None
- return str(value)
-
- return cast(
- AsyncStream[ExecutionUpdateChunk],
- AsyncReconnectingStream(current_stream=initial_stream, stream_creator=create_stream, get_offset=get_offset),
- )
-
- async def stream_stderr_updates(
- self,
- execution_id: str,
- *,
- devbox_id: str,
- offset: 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,
- ) -> AsyncStream[ExecutionUpdateChunk]:
- """
- Tails the stderr logs for the given execution with SSE streaming
-
- Args:
- offset: The byte offset to start the stream from
-
- 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}")
- if extra_headers and extra_headers.get(RAW_RESPONSE_HEADER):
- return await self._get(
- f"/v1/devboxes/{devbox_id}/executions/{execution_id}/stream_stderr_updates",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"offset": offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
- ),
- ),
- cast_to=DevboxAsyncExecutionDetailView,
- stream=True,
- stream_cls=AsyncStream[ExecutionUpdateChunk],
- )
-
- 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",
- options=make_request_options(
- extra_headers=extra_headers,
- extra_query=extra_query,
- extra_body=extra_body,
- timeout=timeout,
- query=await async_maybe_transform(
- {"offset": new_offset}, execution_stream_updates_params.ExecutionStreamUpdatesParams
+ {"offset": new_offset},
+ execution_stream_stdout_updates_params.ExecutionStreamStdoutUpdatesParams,
),
),
cast_to=DevboxAsyncExecutionDetailView,
diff --git a/src/runloop_api_client/types/devboxes/__init__.py b/src/runloop_api_client/types/devboxes/__init__.py
index 43e642744..472d68e9a 100644
--- a/src/runloop_api_client/types/devboxes/__init__.py
+++ b/src/runloop_api_client/types/devboxes/__init__.py
@@ -77,7 +77,6 @@
from .code_action_application_result import CodeActionApplicationResult as CodeActionApplicationResult
from .execution_execute_async_params import ExecutionExecuteAsyncParams as ExecutionExecuteAsyncParams
from .lsp_set_watch_directory_params import LspSetWatchDirectoryParams as LspSetWatchDirectoryParams
-from .execution_stream_updates_params import ExecutionStreamUpdatesParams as ExecutionStreamUpdatesParams
from .lsp_get_code_segment_info_params import LspGetCodeSegmentInfoParams as LspGetCodeSegmentInfoParams
from .lsp_set_watch_directory_response import LspSetWatchDirectoryResponse as LspSetWatchDirectoryResponse
from .computer_mouse_interaction_params import ComputerMouseInteractionParams as ComputerMouseInteractionParams
@@ -91,6 +90,12 @@
from .computer_keyboard_interaction_response import (
ComputerKeyboardInteractionResponse as ComputerKeyboardInteractionResponse,
)
+from .execution_stream_stderr_updates_params import (
+ ExecutionStreamStderrUpdatesParams as ExecutionStreamStderrUpdatesParams,
+)
+from .execution_stream_stdout_updates_params import (
+ ExecutionStreamStdoutUpdatesParams as ExecutionStreamStdoutUpdatesParams,
+)
from .lsp_get_code_actions_for_diagnostic_params import (
LspGetCodeActionsForDiagnosticParams as LspGetCodeActionsForDiagnosticParams,
)
diff --git a/src/runloop_api_client/types/devboxes/execution_kill_params.py b/src/runloop_api_client/types/devboxes/execution_kill_params.py
index 384da945c..0df5c8615 100644
--- a/src/runloop_api_client/types/devboxes/execution_kill_params.py
+++ b/src/runloop_api_client/types/devboxes/execution_kill_params.py
@@ -12,3 +12,7 @@ class ExecutionKillParams(TypedDict, total=False):
devbox_id: Required[str]
kill_process_group: Optional[bool]
+ """Whether to kill the entire process group (default: false).
+
+ If true, kills all processes in the same process group as the target process.
+ """
diff --git a/src/runloop_api_client/types/devboxes/execution_stream_updates_params.py b/src/runloop_api_client/types/devboxes/execution_stream_stderr_updates_params.py
similarity index 70%
rename from src/runloop_api_client/types/devboxes/execution_stream_updates_params.py
rename to src/runloop_api_client/types/devboxes/execution_stream_stderr_updates_params.py
index 3473cbc2c..b82639556 100644
--- a/src/runloop_api_client/types/devboxes/execution_stream_updates_params.py
+++ b/src/runloop_api_client/types/devboxes/execution_stream_stderr_updates_params.py
@@ -4,10 +4,10 @@
from typing_extensions import Required, TypedDict
-__all__ = ["ExecutionStreamUpdatesParams"]
+__all__ = ["ExecutionStreamStderrUpdatesParams"]
-class ExecutionStreamUpdatesParams(TypedDict, total=False):
+class ExecutionStreamStderrUpdatesParams(TypedDict, total=False):
devbox_id: Required[str]
offset: str
diff --git a/src/runloop_api_client/types/devboxes/execution_stream_stdout_updates_params.py b/src/runloop_api_client/types/devboxes/execution_stream_stdout_updates_params.py
new file mode 100644
index 000000000..7296156b0
--- /dev/null
+++ b/src/runloop_api_client/types/devboxes/execution_stream_stdout_updates_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__ = ["ExecutionStreamStdoutUpdatesParams"]
+
+
+class ExecutionStreamStdoutUpdatesParams(TypedDict, total=False):
+ devbox_id: Required[str]
+
+ offset: str
+ """The byte offset to start the stream from"""
diff --git a/src/runloop_api_client/types/devboxes/execution_update_chunk.py b/src/runloop_api_client/types/devboxes/execution_update_chunk.py
index f5366d0cb..eda7add55 100644
--- a/src/runloop_api_client/types/devboxes/execution_update_chunk.py
+++ b/src/runloop_api_client/types/devboxes/execution_update_chunk.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
from typing import Optional
-from typing_extensions import Literal
from ..._models import BaseModel
@@ -9,32 +8,8 @@
class ExecutionUpdateChunk(BaseModel):
- devbox_id: str
- """Devbox id where command was executed."""
+ output: str
+ """The latest log stream chunk."""
- execution_id: str
- """Ephemeral id of the execution in progress."""
-
- status: Literal["queued", "running", "completed"]
- """Current status of the execution."""
-
- exit_status: Optional[int] = None
- """Exit code of command execution.
-
- This field will remain unset until the execution has completed.
- """
-
- shell_name: Optional[str] = None
- """Shell name."""
-
- stderr: Optional[str] = None
- """Standard error generated by command.
-
- This field will remain unset until the execution has completed.
- """
-
- stdout: Optional[str] = None
- """Standard out generated by command.
-
- This field will remain unset until the execution has completed.
- """
+ offset: Optional[int] = None
+ """The byte offset of this chunk of log stream."""
diff --git a/tests/test_client.py b/tests/test_client.py
index cb84f9ebe..ca53896b3 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -6,13 +6,10 @@
import os
import sys
import json
-import time
import asyncio
import inspect
-import subprocess
import tracemalloc
from typing import Any, Union, cast
-from textwrap import dedent
from unittest import mock
from typing_extensions import Literal
@@ -23,14 +20,17 @@
from runloop_api_client import Runloop, AsyncRunloop, APIResponseValidationError
from runloop_api_client._types import Omit
+from runloop_api_client._utils import asyncify
from runloop_api_client._models import BaseModel, FinalRequestOptions
from runloop_api_client._exceptions import RunloopError, APIStatusError, APITimeoutError, APIResponseValidationError
from runloop_api_client._base_client import (
DEFAULT_TIMEOUT,
HTTPX_DEFAULT_TIMEOUT,
BaseClient,
+ OtherPlatform,
DefaultHttpxClient,
DefaultAsyncHttpxClient,
+ get_platform,
make_request_options,
)
@@ -1727,50 +1727,9 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
assert response.http_request.headers.get("x-stainless-retry-count") == "42"
- def test_get_platform(self) -> None:
- # A previous implementation of asyncify could leave threads unterminated when
- # used with nest_asyncio.
- #
- # Since nest_asyncio.apply() is global and cannot be un-applied, this
- # test is run in a separate process to avoid affecting other tests.
- test_code = dedent("""
- import asyncio
- import nest_asyncio
- import threading
-
- from runloop_api_client._utils import asyncify
- from runloop_api_client._base_client import get_platform
-
- async def test_main() -> None:
- result = await asyncify(get_platform)()
- print(result)
- for thread in threading.enumerate():
- print(thread.name)
-
- nest_asyncio.apply()
- asyncio.run(test_main())
- """)
- with subprocess.Popen(
- [sys.executable, "-c", test_code],
- text=True,
- ) as process:
- timeout = 10 # seconds
-
- start_time = time.monotonic()
- while True:
- return_code = process.poll()
- if return_code is not None:
- if return_code != 0:
- raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code")
-
- # success
- break
-
- if time.monotonic() - start_time > timeout:
- process.kill()
- raise AssertionError("calling get_platform using asyncify resulted in a hung process")
-
- time.sleep(0.1)
+ async def test_get_platform(self) -> None:
+ platform = await asyncify(get_platform)()
+ assert isinstance(platform, (str, OtherPlatform))
async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None:
# Test that the proxy environment variables are set correctly