Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/python-sdk-dedupe-create-response.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@e2b/python-sdk': patch
'e2b': patch
---

Share the sandbox create/connect/fork response mapping (JS and Python) and the Python `Commands.run` / `Commands.connect` handle setup
54 changes: 24 additions & 30 deletions packages/js-sdk/src/sandbox/sandboxApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -572,15 +572,27 @@ function validateForkCount(count: number | undefined) {
}
}

type SandboxForkResponse =
| {
sandboxId: string
sandboxDomain?: string
envdVersion: string
envdAccessToken?: string
trafficAccessToken?: string
}
| Error
type SandboxCreateResponse = {
sandboxId: string
sandboxDomain?: string
envdVersion: string
envdAccessToken?: string
trafficAccessToken?: string
}

type SandboxForkResponse = SandboxCreateResponse | Error

function toSandboxCreateResponse(
sandbox: components['schemas']['Sandbox']
): SandboxCreateResponse {
return {
sandboxId: sandbox.sandboxID,
sandboxDomain: sandbox.domain || undefined,
envdVersion: sandbox.envdVersion,
envdAccessToken: sandbox.envdAccessToken,
trafficAccessToken: sandbox.trafficAccessToken || undefined,
}
}

/**
* Options for creating a new Sandbox.
Expand Down Expand Up @@ -1761,13 +1773,7 @@ export class SandboxApi extends ClientFactory {
)
}

return {
sandboxId: res.data!.sandboxID,
sandboxDomain: res.data!.domain || undefined,
envdVersion: res.data!.envdVersion,
envdAccessToken: res.data!.envdAccessToken,
trafficAccessToken: res.data!.trafficAccessToken || undefined,
}
return toSandboxCreateResponse(res.data!)
}

protected static async forkSandbox(
Expand Down Expand Up @@ -1827,13 +1833,7 @@ export class SandboxApi extends ClientFactory {
return apiErrorFromCode(result.error.code, result.error.message)
}

return {
sandboxId: result.sandbox.sandboxID,
sandboxDomain: result.sandbox.domain || undefined,
envdVersion: result.sandbox.envdVersion,
envdAccessToken: result.sandbox.envdAccessToken,
trafficAccessToken: result.sandbox.trafficAccessToken || undefined,
}
return toSandboxCreateResponse(result.sandbox)
}
)
}
Expand Down Expand Up @@ -1883,13 +1883,7 @@ export class SandboxApi extends ClientFactory {
throw err
}

return {
sandboxId: res.data!.sandboxID,
sandboxDomain: res.data!.domain || undefined,
envdVersion: res.data!.envdVersion,
envdAccessToken: res.data!.envdAccessToken,
trafficAccessToken: res.data!.trafficAccessToken || undefined,
}
return toSandboxCreateResponse(res.data!)
}
}

Expand Down
21 changes: 21 additions & 0 deletions packages/python-sdk/e2b/sandbox/sandbox_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
from e2b.api.client.models import (
SandboxNetworkUpdateConfigRules,
)
from e2b.api import SandboxCreateResponse
from e2b.api.client.models.sandbox import Sandbox as CreatedSandbox
from e2b.api.client.types import UNSET, Unset
from e2b.connection_config import ApiParams
from e2b.exceptions import InvalidArgumentException
Expand All @@ -76,6 +78,25 @@
MAX_FORK_COUNT = 20


def to_sandbox_create_response(sandbox: CreatedSandbox) -> SandboxCreateResponse:
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
"""Map a created, connected or forked sandbox from the API response."""
return SandboxCreateResponse(
sandbox_id=sandbox.sandbox_id,
sandbox_domain=sandbox.domain if isinstance(sandbox.domain, str) else None,
envd_version=sandbox.envd_version,
envd_access_token=(
sandbox.envd_access_token
if isinstance(sandbox.envd_access_token, str)
else None
),
traffic_access_token=(
sandbox.traffic_access_token
if isinstance(sandbox.traffic_access_token, str)
else None
),
)


def validate_fork_count(count: Any) -> None:
"""Reject a fork count the SDK will not send.
Expand Down
47 changes: 19 additions & 28 deletions packages/python-sdk/e2b/sandbox_async/commands/command.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Literal, Optional, Union, overload
from typing import Any, AsyncGenerator, Dict, List, Literal, Optional, Union, overload

import httpx
from connectrpc.code import Code
Expand Down Expand Up @@ -315,32 +315,9 @@ async def _start(
)
)

try:
start_event = await first_event(
events, self._connection_config.get_request_timeout(request_timeout)
)

pid = extract_start_pid(start_event, "start process")
return AsyncCommandHandle(
pid=pid,
handle_kill=lambda: self.kill(pid),
events=events,
on_stdout=on_stdout,
on_stderr=on_stderr,
handle_send_stdin=lambda data, request_timeout=None: self.send_stdin(
pid, data, request_timeout
),
handle_close_stdin=lambda request_timeout=None: self.close_stdin(
pid, request_timeout
),
check_health=self._check_health,
)
except Exception as e:
try:
await events.aclose()
except Exception:
pass
raise await ahandle_rpc_exception_with_health(e, self._check_health)
return await self._create_handle(
events, "start process", request_timeout, on_stdout, on_stderr
)

async def connect(
self,
Expand Down Expand Up @@ -374,12 +351,26 @@ async def connect(
)
)

return await self._create_handle(
events, "connect to process", request_timeout, on_stdout, on_stderr
)

async def _create_handle(
self,
events: AsyncGenerator[
Union[process_pb.StartResponse, process_pb.ConnectResponse], Any
],
action: str,
request_timeout: Optional[float],
on_stdout: Optional[OutputHandler[Stdout]],
on_stderr: Optional[OutputHandler[Stderr]],
) -> AsyncCommandHandle:
try:
start_event = await first_event(
events, self._connection_config.get_request_timeout(request_timeout)
)

pid = extract_start_pid(start_event, "connect to process")
pid = extract_start_pid(start_event, action)
return AsyncCommandHandle(
pid=pid,
handle_kill=lambda: self.kill(pid),
Expand Down
63 changes: 4 additions & 59 deletions packages/python-sdk/e2b/sandbox_async/sandbox_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
build_iam_config,
build_lifecycle_config,
build_network_config,
to_sandbox_create_response,
validate_fork_count,
)
from e2b.sandbox_async.paginator import AsyncSandboxPaginator
Expand Down Expand Up @@ -269,25 +270,7 @@ async def _create_sandbox(
"You need to update the template to use the new SDK."
)

domain = res.parsed.domain if isinstance(res.parsed.domain, str) else None
envd_token = (
res.parsed.envd_access_token
if isinstance(res.parsed.envd_access_token, str)
else None
)
traffic_token = (
res.parsed.traffic_access_token
if isinstance(res.parsed.traffic_access_token, str)
else None
)

return SandboxCreateResponse(
sandbox_id=res.parsed.sandbox_id,
sandbox_domain=domain,
envd_version=res.parsed.envd_version,
envd_access_token=envd_token,
traffic_access_token=traffic_token,
)
return to_sandbox_create_response(res.parsed)

@classmethod
async def _cls_get_metrics(
Expand Down Expand Up @@ -496,27 +479,7 @@ async def _cls_fork(
results.append(exception)
continue

domain = sandbox.domain if isinstance(sandbox.domain, str) else None
envd_token = (
sandbox.envd_access_token
if isinstance(sandbox.envd_access_token, str)
else None
)
traffic_token = (
sandbox.traffic_access_token
if isinstance(sandbox.traffic_access_token, str)
else None
)

results.append(
SandboxCreateResponse(
sandbox_id=sandbox.sandbox_id,
sandbox_domain=domain,
envd_version=sandbox.envd_version,
envd_access_token=envd_token,
traffic_access_token=traffic_token,
)
)
results.append(to_sandbox_create_response(sandbox))

return results

Expand Down Expand Up @@ -556,22 +519,4 @@ async def _cls_connect(
if res.parsed is None:
raise Exception("Body of the request is None")

domain = res.parsed.domain if isinstance(res.parsed.domain, str) else None
envd_token = (
res.parsed.envd_access_token
if isinstance(res.parsed.envd_access_token, str)
else None
)
traffic_token = (
res.parsed.traffic_access_token
if isinstance(res.parsed.traffic_access_token, str)
else None
)

return SandboxCreateResponse(
sandbox_id=res.parsed.sandbox_id,
sandbox_domain=domain,
envd_version=res.parsed.envd_version,
envd_access_token=envd_token,
traffic_access_token=traffic_token,
)
return to_sandbox_create_response(res.parsed)
46 changes: 22 additions & 24 deletions packages/python-sdk/e2b/sandbox_sync/commands/command.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
from typing import Callable, Dict, List, Literal, Optional, Union, overload
from typing import (
Any,
Callable,
Dict,
Generator,
List,
Literal,
Optional,
Union,
overload,
)

import httpx
from connectrpc.code import Code
Expand Down Expand Up @@ -315,28 +325,7 @@ def _start(
)
)

try:
start_event = events.__next__()

pid = extract_start_pid(start_event, "start process")
return CommandHandle(
pid=pid,
handle_kill=lambda: self.kill(pid),
events=events,
handle_send_stdin=lambda data, request_timeout=None: self.send_stdin(
pid, data, request_timeout
),
handle_close_stdin=lambda request_timeout=None: self.close_stdin(
pid, request_timeout
),
check_health=self._check_health,
)
except Exception as e:
try:
events.close()
except Exception:
pass
raise handle_rpc_exception_with_health(e, self._check_health)
return self._create_handle(events, "start process")

def connect(
self,
Expand Down Expand Up @@ -366,10 +355,19 @@ def connect(
)
)

return self._create_handle(events, "connect to process")

def _create_handle(
self,
events: Generator[
Union[process_pb.StartResponse, process_pb.ConnectResponse], Any, None
],
action: str,
) -> CommandHandle:
try:
start_event = events.__next__()

pid = extract_start_pid(start_event, "connect to process")
pid = extract_start_pid(start_event, action)
return CommandHandle(
pid=pid,
handle_kill=lambda: self.kill(pid),
Expand Down
Loading
Loading