Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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/olive-poets-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'e2b': minor
'@e2b/python-sdk': minor
---

Remove SDK-side defaults from API request payloads so the API defaults apply when options are omitted. Sandbox create/fork no longer preset a 5-minute timeout, fork no longer presets `count: 1`, create no longer presets `allow_internet_access` (sandboxes remain `secure` by default), pause no longer presets keeping memory, and template builds no longer preset CPU/memory. Explicitly provided values are still sent unchanged.
8 changes: 3 additions & 5 deletions packages/js-sdk/src/sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createConnectTransport } from '@connectrpc/connect-web'
import {
ConnectionConfig,
ConnectionOpts,
DEFAULT_SANDBOX_TIMEOUT_MS,
defaultUsername,
Username,
} from '../connectionConfig'
Expand Down Expand Up @@ -76,7 +75,6 @@ export interface SandboxUrlOpts {
export class Sandbox extends SandboxApi {
protected static readonly defaultTemplate: string = 'base'
protected static readonly defaultMcpTemplate: string = 'mcp-gateway'
protected static readonly defaultSandboxTimeoutMs = DEFAULT_SANDBOX_TIMEOUT_MS
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.

/**
* Module for interacting with the sandbox filesystem
Expand Down Expand Up @@ -317,7 +315,7 @@ export class Sandbox extends SandboxApi {

const sandboxInfo = await this.createSandbox(
template,
apiOpts?.timeoutMs ?? this.defaultSandboxTimeoutMs,
apiOpts?.timeoutMs,
apiOpts
)

Expand Down Expand Up @@ -433,8 +431,8 @@ export class Sandbox extends SandboxApi {

const results = await this.forkSandbox(
sandboxId,
apiOpts?.timeoutMs ?? this.defaultSandboxTimeoutMs,
apiOpts?.count ?? 1,
apiOpts?.timeoutMs,
apiOpts?.count,
apiOpts
)

Expand Down
30 changes: 10 additions & 20 deletions packages/js-sdk/src/sandbox/sandboxApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,6 @@ export interface SandboxPauseOpts extends SandboxApiOpts {
* When `false`, the in-memory state is dropped and only the filesystem is
* persisted (a filesystem-only snapshot); resuming such a sandbox cold-boots
* (reboots) it from disk, losing running processes and open connections.
*
* @default true
*/
keepMemory?: boolean
}
Expand All @@ -529,16 +527,12 @@ export interface SandboxForkOpts extends ConnectionOpts {
* All forks boot from the same snapshot — the snapshot is captured once
* regardless of count. Each fork succeeds or fails independently; the
* outcome of each is reported in its entry of the returned array.
*
* @default 1
*/
count?: number

/**
* Timeout for the forked sandboxes in **milliseconds**.
* Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users.
*
* @default 300_000 // 5 minutes
*/
timeoutMs?: number
}
Expand Down Expand Up @@ -590,8 +584,6 @@ export interface SandboxOpts extends ConnectionOpts {
/**
* Timeout for the sandbox in **milliseconds**.
* Maximum time a sandbox can be kept alive is 24 hours (86_400_000 milliseconds) for Pro users and 1 hour (3_600_000 milliseconds) for Hobby users.
*
* @default 300_000 // 5 minutes
*/
timeoutMs?: number

Expand All @@ -604,8 +596,6 @@ export interface SandboxOpts extends ConnectionOpts {

/**
* Allow sandbox to access the internet. If set to `False`, it works the same as setting network `denyOut` to `[0.0.0.0/0]`.
*
* @default true
*/
allowInternetAccess?: boolean

Expand Down Expand Up @@ -714,8 +704,6 @@ export interface SandboxListOpts extends Omit<SandboxApiOpts, 'signal'> {
/**
* Sort order of the list of sandboxes by start time, applied across the
* whole result set before pagination (not within a page).
*
* @default 'desc'
*/
order?: SandboxListOrder

Expand Down Expand Up @@ -1475,7 +1463,7 @@ export class SandboxApi extends ClientFactory {
},
},
body: {
memory: apiOpts?.keepMemory ?? true,
memory: apiOpts?.keepMemory,
},
signal: config.getSignal(apiOpts?.requestTimeoutMs, apiOpts?.signal),
})
Expand Down Expand Up @@ -1602,7 +1590,7 @@ export class SandboxApi extends ClientFactory {

protected static async createSandbox(
template: string,
timeoutMs: number,
timeoutMs?: number,
opts?: SandboxOpts
) {
const apiOpts = this.resolveOpts(opts)
Expand Down Expand Up @@ -1656,9 +1644,10 @@ export class SandboxApi extends ClientFactory {
metadata: opts?.metadata,
mcp: opts?.mcp as Record<string, unknown> | undefined,
envVars: opts?.envs,
timeout: timeoutToSeconds(timeoutMs),
timeout:
timeoutMs === undefined ? undefined : timeoutToSeconds(timeoutMs),
secure: opts?.secure ?? true,
allow_internet_access: opts?.allowInternetAccess ?? true,
allow_internet_access: opts?.allowInternetAccess,
network: buildNetworkBody(opts?.network, iam),
iam,
autoPause: onTimeoutConfigured ? action === 'pause' : undefined,
Expand Down Expand Up @@ -1705,11 +1694,11 @@ export class SandboxApi extends ClientFactory {

protected static async forkSandbox(
sandboxId: string,
timeoutMs: number,
count: number,
timeoutMs?: number,
count?: number,
opts?: SandboxApiOpts
): Promise<SandboxForkResponse[]> {
if (count < 1) {
if (count !== undefined && count < 1) {
throw new InvalidArgumentError('count must be at least 1')
}
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Outdated

Expand All @@ -1724,7 +1713,8 @@ export class SandboxApi extends ClientFactory {
},
},
body: {
timeout: timeoutToSeconds(timeoutMs),
timeout:
timeoutMs === undefined ? undefined : timeoutToSeconds(timeoutMs),
count,
},
signal: config.getSignal(apiOpts?.requestTimeoutMs, apiOpts?.signal),
Expand Down
4 changes: 2 additions & 2 deletions packages/js-sdk/src/template/buildApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
type RequestBuildInput = {
name: string
tags?: string[]
cpuCount: number
memoryMB: number
cpuCount?: number
memoryMB?: number
}

type GetFileUploadLinkInput = {
Expand Down
4 changes: 2 additions & 2 deletions packages/js-sdk/src/template/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1076,8 +1076,8 @@ export class TemplateBase
{
name,
tags: options.tags,
cpuCount: options.cpuCount ?? 2,
memoryMB: options.memoryMB ?? 1024,
cpuCount: options.cpuCount,
memoryMB: options.memoryMB,
},
config.getSignal(undefined, options.signal)
)
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
Expand Down
2 changes: 0 additions & 2 deletions packages/js-sdk/src/template/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ export type BasicBuildOptions = {
tags?: string[]
/**
* Number of CPUs allocated to the sandbox.
* @default 2
*/
cpuCount?: number
/**
* Amount of memory in MB allocated to the sandbox.
* @default 1024
*/
memoryMB?: number
/**
Expand Down
105 changes: 105 additions & 0 deletions packages/js-sdk/tests/sandbox/apiDefaults.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { afterAll, afterEach, beforeAll, expect, test } from 'vitest'
import { http, HttpResponse } from 'msw'
import { setupServer } from 'msw/node'

import { Sandbox } from '../../src'
import { TEST_API_KEY, apiUrl } from '../setup'

let lastCreateBody: Record<string, unknown> | undefined
let lastForkBody: Record<string, unknown> | undefined
let lastPauseBody: Record<string, unknown> | undefined

const server = setupServer(
http.post(apiUrl('/sandboxes'), async ({ request }) => {
lastCreateBody = (await request.json()) as Record<string, unknown>
return HttpResponse.json({
sandboxID: 'test-sandbox-id',
templateID: 'base',
envdVersion: '0.2.4',
})
}),
http.post(apiUrl('/sandboxes/:sandboxID/fork'), async ({ request }) => {
lastForkBody = (await request.json()) as Record<string, unknown>
return HttpResponse.json([
{
sandbox: {
sandboxID: 'forked-sandbox-id',
templateID: 'base',
envdVersion: '0.2.4',
},
},
])
}),
http.post(apiUrl('/sandboxes/:sandboxID/pause'), async ({ request }) => {
lastPauseBody = (await request.json()) as Record<string, unknown>
return new HttpResponse(null, { status: 204 })
})
)

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))

afterAll(() => server.close())

afterEach(() => {
lastCreateBody = undefined
lastForkBody = undefined
lastPauseBody = undefined
server.resetHandlers()
})

test('Sandbox.create omits timeout and allow_internet_access when unset and defaults secure to true', async () => {
await Sandbox.create('base', { apiKey: TEST_API_KEY })

expect(lastCreateBody).toBeDefined()
expect(lastCreateBody).not.toHaveProperty('timeout')
expect(lastCreateBody?.secure).toBe(true)
expect(lastCreateBody).not.toHaveProperty('allow_internet_access')
})

test('Sandbox.create sends explicit timeout, secure and allow_internet_access', async () => {
await Sandbox.create('base', {
apiKey: TEST_API_KEY,
timeoutMs: 60_000,
secure: false,
allowInternetAccess: false,
})

expect(lastCreateBody?.timeout).toBe(60)
expect(lastCreateBody?.secure).toBe(false)
expect(lastCreateBody?.allow_internet_access).toBe(false)
})

test('Sandbox.fork omits timeout and count when unset', async () => {
await Sandbox.fork('test-sandbox-id', { apiKey: TEST_API_KEY })

expect(lastForkBody).toBeDefined()
expect(lastForkBody).not.toHaveProperty('timeout')
expect(lastForkBody).not.toHaveProperty('count')
})

test('Sandbox.fork sends explicit timeout and count', async () => {
await Sandbox.fork('test-sandbox-id', {
apiKey: TEST_API_KEY,
timeoutMs: 60_000,
count: 2,
})

expect(lastForkBody?.timeout).toBe(60)
expect(lastForkBody?.count).toBe(2)
})

test('Sandbox.pause omits memory when keepMemory is unset', async () => {
await Sandbox.pause('test-sandbox-id', { apiKey: TEST_API_KEY })

expect(lastPauseBody).toBeDefined()
expect(lastPauseBody).not.toHaveProperty('memory')
})

test('Sandbox.pause sends an explicit keepMemory', async () => {
await Sandbox.pause('test-sandbox-id', {
apiKey: TEST_API_KEY,
keepMemory: false,
})

expect(lastPauseBody?.memory).toBe(false)
})
1 change: 1 addition & 0 deletions packages/js-sdk/tests/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const sandboxTest = base.extend<SandboxFixture>({
async ({ sandboxTestId, sandboxOpts }, use) => {
const sandbox = await Sandbox.create(template, {
metadata: { sandboxTestId },
timeoutMs: 300_000,
...sandboxOpts,
})
onTestFailed(() => {
Expand Down
Loading
Loading