Skip to content

Commit d0caf3e

Browse files
authored
feat(sdk)!: remove named shell helpers and API references (#16)
1 parent dd3fa4a commit d0caf3e

13 files changed

Lines changed: 52 additions & 918 deletions

File tree

‎README-SDK.md‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ async with await runloop.devbox.create(name="temp-devbox") as devbox:
437437

438438
#### Devbox Logs
439439

440-
Retrieve logs from a devbox, optionally filtered by execution ID or shell name:
440+
Retrieve logs from a devbox, optionally filtered by execution ID:
441441

442442
```python
443443
# Get all devbox logs
@@ -448,17 +448,14 @@ for log in logs.logs:
448448
# Filter logs by execution ID
449449
result = devbox.cmd.exec('echo "hello"')
450450
exec_logs = devbox.logs(execution_id=result.execution_id)
451-
452-
# Filter logs by shell name
453-
shell_logs = devbox.logs(shell_name="my-shell")
454451
```
455452

456453
**Key methods:**
457454

458455
- `devbox.get_info()` - Get devbox details and status
459456
- `devbox.cmd.exec()` - Execute commands synchronously
460457
- `devbox.cmd.exec_async()` - Execute commands asynchronously
461-
- `devbox.logs()` - Retrieve devbox logs (optionally filter by execution_id or shell_name)
458+
- `devbox.logs()` - Retrieve devbox logs (optionally filter by execution_id)
462459
- `devbox.file.read()` - Read file contents
463460
- `devbox.file.write()` - Write file contents
464461
- `devbox.file.upload()` - Upload files

‎src/runloop_api_client/sdk/__init__.py‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@
3333
AsyncNetworkPolicyOps,
3434
AsyncStorageObjectOps,
3535
)
36-
from .devbox import Devbox, NamedShell
36+
from .devbox import Devbox
3737
from .secret import Secret
3838
from .snapshot import Snapshot
3939
from .blueprint import Blueprint
4040
from .execution import Execution
4141
from .async_axon import AsyncAxon, AsyncAxonSqlOps
4242
from .mcp_config import McpConfig
4343
from .async_agent import AsyncAgent
44-
from .async_devbox import AsyncDevbox, AsyncNamedShell
44+
from .async_devbox import AsyncDevbox
4545
from .async_secret import AsyncSecret
4646
from .secret_by_id import SecretById
4747
from .async_snapshot import AsyncSnapshot
@@ -113,6 +113,4 @@
113113
"AsyncMcpConfig",
114114
"GatewayConfig",
115115
"AsyncGatewayConfig",
116-
"NamedShell",
117-
"AsyncNamedShell",
118116
]

‎src/runloop_api_client/sdk/_types.py‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
from ..types.devbox_create_params import DevboxBaseCreateParams
3838
from ..types.axons.sql_batch_params import SqlBatchParams
3939
from ..types.axons.sql_query_params import SqlQueryParams
40-
from ..types.devbox_execute_async_params import DevboxNiceExecuteAsyncParams
4140

4241
LogCallback = Callable[[str], None]
4342

@@ -89,11 +88,17 @@ class SDKDevboxCreateFromImageParams(DevboxBaseCreateParams, LongPollingRequestO
8988
pass
9089

9190

92-
class SDKDevboxExecuteParams(DevboxNiceExecuteAsyncParams, ExecuteStreamingCallbacks, LongPollingRequestOptions):
91+
class DevboxCommandOptions(TypedDict, total=False):
92+
"""Optional API fields shared by command execution helpers."""
93+
94+
attach_stdin: Optional[bool]
95+
96+
97+
class SDKDevboxExecuteParams(DevboxCommandOptions, ExecuteStreamingCallbacks, LongPollingRequestOptions):
9398
pass
9499

95100

96-
class SDKDevboxExecuteAsyncParams(DevboxNiceExecuteAsyncParams, ExecuteStreamingCallbacks, LongRequestOptions):
101+
class SDKDevboxExecuteAsyncParams(DevboxCommandOptions, ExecuteStreamingCallbacks, LongRequestOptions):
97102
pass
98103

99104

‎src/runloop_api_client/sdk/async_devbox.py‎

Lines changed: 4 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
LogCallback,
1818
BaseRequestOptions,
1919
LongRequestOptions,
20+
DevboxCommandOptions,
2021
PollingRequestOptions,
2122
SDKDevboxExecuteParams,
2223
ExecuteStreamingCallbacks,
@@ -38,7 +39,6 @@
3839
from ..types.devboxes import ExecutionUpdateChunk
3940
from .async_execution import AsyncExecution, _AsyncStreamingGroup
4041
from .async_execution_result import AsyncExecutionResult
41-
from ..types.devbox_execute_async_params import DevboxNiceExecuteAsyncParams
4242
from ..types.devboxes.devbox_logs_list_view import DevboxLogsListView
4343
from ..types.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView
4444

@@ -168,18 +168,15 @@ async def logs(
168168
self,
169169
*,
170170
execution_id: str | None = None,
171-
shell_name: str | None = None,
172171
**options: Unpack[BaseRequestOptions],
173172
) -> DevboxLogsListView:
174173
"""Retrieve logs for the devbox.
175174
176175
Returns all logs from a running or completed devbox. Optionally filter
177-
by execution ID or shell name.
176+
by execution ID.
178177
179178
:param execution_id: Filter logs by execution ID, defaults to None
180179
:type execution_id: str | None, optional
181-
:param shell_name: Filter logs by shell name, defaults to None
182-
:type shell_name: str | None, optional
183180
:param options: Optional request configuration
184181
:return: Log entries for the devbox
185182
:rtype: :class:`~runloop_api_client.types.devboxes.devbox_logs_list_view.DevboxLogsListView`
@@ -192,7 +189,6 @@ async def logs(
192189
return await self._client.devboxes.logs.list(
193190
self._id,
194191
execution_id=execution_id if execution_id is not None else omit,
195-
shell_name=shell_name if shell_name is not None else omit,
196192
**options,
197193
)
198194

@@ -376,39 +372,6 @@ def net(self) -> AsyncNetworkInterface:
376372
"""
377373
return AsyncNetworkInterface(self)
378374

379-
def shell(self, shell_name: str | None = None) -> AsyncNamedShell:
380-
"""Create a named shell instance for stateful command execution.
381-
382-
Named shells are stateful and maintain environment variables and the current working
383-
directory (CWD) across commands, just like a real shell on your local computer.
384-
Commands executed through the same named shell instance will execute sequentially -
385-
the shell can only run one command at a time with automatic queuing. This ensures
386-
that environment changes and directory changes from one command are preserved for
387-
the next command.
388-
389-
:param shell_name: The name of the persistent shell session. If not provided, a UUID will be generated automatically.
390-
:type shell_name: str | None, optional
391-
:return: An AsyncNamedShell instance for executing commands in the named shell
392-
:rtype: AsyncNamedShell
393-
394-
Example:
395-
>>> # Create a named shell with a custom name
396-
>>> shell = await devbox.shell("my-session")
397-
>>> # Create a named shell with an auto-generated UUID name
398-
>>> shell2 = await devbox.shell()
399-
>>> # Commands execute sequentially and share state
400-
>>> await shell.exec("cd /app")
401-
>>> await shell.exec("export MY_VAR=value")
402-
>>> result = await shell.exec("echo $MY_VAR") # Will output 'value'
403-
>>> result = await shell.exec("pwd") # Will output '/app'
404-
"""
405-
if shell_name is None:
406-
# uuid_utils is not typed
407-
from uuid_utils import uuid7 # type: ignore
408-
409-
shell_name = str(uuid7())
410-
return AsyncNamedShell(self, shell_name)
411-
412375
# ------------------------------------------------------------------ #
413376
# Internal helpers
414377
# ------------------------------------------------------------------ #
@@ -519,7 +482,7 @@ async def exec(
519482
execution: DevboxAsyncExecutionDetailView = await client.devboxes.execute_async(
520483
devbox.id,
521484
command=command,
522-
**filter_params(params, DevboxNiceExecuteAsyncParams),
485+
**filter_params(params, DevboxCommandOptions),
523486
**filter_params(params, LongRequestOptions),
524487
)
525488
streaming_group = devbox._start_streaming(
@@ -579,7 +542,7 @@ async def exec_async(
579542
execution: DevboxAsyncExecutionDetailView = await client.devboxes.execute_async(
580543
devbox.id,
581544
command=command,
582-
**filter_params(params, DevboxNiceExecuteAsyncParams),
545+
**filter_params(params, DevboxCommandOptions),
583546
**filter_params(params, LongRequestOptions),
584547
)
585548

@@ -681,103 +644,6 @@ async def upload(
681644
)
682645

683646

684-
class AsyncNamedShell:
685-
"""Interface for executing commands in a persistent, stateful shell session.
686-
687-
Named shells are stateful and maintain environment variables and the current working
688-
directory (CWD) across commands. Commands executed through the same named shell
689-
instance will execute sequentially - the shell can only run one command at a time
690-
with automatic queuing. This ensures that environment changes and directory changes
691-
from one command are preserved for the next command.
692-
693-
Use :meth:`AsyncDevbox.shell` to create a named shell instance. If you use the same
694-
shell name, it will re-attach to the existing named shell, preserving its state.
695-
696-
Example:
697-
>>> shell = await devbox.shell("my-session")
698-
>>> await shell.exec("cd /app")
699-
>>> await shell.exec("export MY_VAR=value")
700-
>>> result = await shell.exec("echo $MY_VAR") # Will output 'value'
701-
>>> result = await shell.exec("pwd") # Will output '/app'
702-
"""
703-
704-
def __init__(self, devbox: AsyncDevbox, shell_name: str) -> None:
705-
"""Initialize the named shell.
706-
707-
:param devbox: The async devbox instance to execute commands on
708-
:type devbox: AsyncDevbox
709-
:param shell_name: The name of the persistent shell session
710-
:type shell_name: str
711-
"""
712-
self._devbox = devbox
713-
self._shell_name = shell_name
714-
715-
async def exec(
716-
self,
717-
command: str,
718-
**params: Unpack[SDKDevboxExecuteParams],
719-
) -> AsyncExecutionResult:
720-
"""Execute a command in the named shell and wait for it to complete.
721-
722-
The command will execute in the persistent shell session, maintaining environment
723-
variables and the current working directory from previous commands. Commands are
724-
queued and execute sequentially - only one command runs at a time in the named shell.
725-
726-
Optionally provide callbacks to stream logs in real-time. When callbacks are provided,
727-
this method waits for both the command to complete AND all streaming data to be
728-
processed before returning.
729-
730-
:param command: The command to execute
731-
:type command: str
732-
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxExecuteParams` for available parameters
733-
:return: Wrapper with exit status and output helpers
734-
:rtype: AsyncExecutionResult
735-
736-
Example:
737-
>>> shell = await devbox.shell("my-session")
738-
>>> result = await shell.exec("ls -la")
739-
>>> print(await result.stdout())
740-
>>> # With streaming callbacks
741-
>>> result = await shell.exec("npm install", stdout=lambda line: print(f"[LOG] {line}"))
742-
"""
743-
# Ensure shell_name is set and cannot be overridden by user params
744-
params["shell_name"] = self._shell_name
745-
return await self._devbox.cmd.exec(command, **params)
746-
747-
async def exec_async(
748-
self,
749-
command: str,
750-
**params: Unpack[SDKDevboxExecuteAsyncParams],
751-
) -> AsyncExecution:
752-
"""Execute a command in the named shell asynchronously without waiting for completion.
753-
754-
The command will execute in the persistent shell session, maintaining environment
755-
variables and the current working directory from previous commands. Commands are
756-
queued and execute sequentially - only one command runs at a time in the named shell.
757-
758-
Optionally provide callbacks to stream logs in real-time as they are produced.
759-
Callbacks fire in real-time as logs arrive. When you call execution.result(),
760-
it will wait for both the command to complete and all streaming to finish.
761-
762-
:param command: The command to execute
763-
:type command: str
764-
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxExecuteAsyncParams` for available parameters
765-
:return: Handle for managing the running process
766-
:rtype: AsyncExecution
767-
768-
Example:
769-
>>> shell = await devbox.shell("my-session")
770-
>>> execution = await shell.exec_async("long-running-task.sh", stdout=lambda line: print(f"[LOG] {line}"))
771-
>>> # Do other work while command runs...
772-
>>> result = await execution.result()
773-
>>> if result.success:
774-
... print("Task completed successfully!")
775-
"""
776-
# Ensure shell_name is set and cannot be overridden by user params
777-
params["shell_name"] = self._shell_name
778-
return await self._devbox.cmd.exec_async(command, **params)
779-
780-
781647
class AsyncNetworkInterface:
782648
"""Interface for networking operations on a devbox.
783649

0 commit comments

Comments
 (0)