Skip to content

Commit 96c67e9

Browse files
feat(sandbox): add Daytona as a manual-flip failover for E2B (#5860)
* feat(sandbox): add Daytona as a manual-flip failover for E2B E2B was a hard single point of failure: lib/execution/e2b.ts had no retry and no fallback, so a failed Sandbox.create() killed Python function blocks, JS-with-imports, shell, doc generation and the Pi cloud agent outright. Extract a SandboxRunner boundary (lib/execution/remote-sandbox) with an E2B runner and a Daytona runner, selected once per execution by the sandbox-provider-daytona AppConfig flag. Everything above the provider boundary — marker parsing, mount materialization, file export, corruption handling — is unchanged. Selection resolves before create() and never mid-execution, since user code has side effects. Each sandbox kind fails closed when its snapshot id is unset. Notes on the Daytona adapter: - language binds at create(), not per call: Daytona applies it as a sandbox label and silently runs JS through Python if passed to codeRun - Python routes via CodeInterpreter for its {name,value,traceback} error shape, which matches E2B's and keeps formatE2BError's line offsets correct - timeouts convert ms to seconds - the streaming path delivers env via the filesystem API, as SessionExecuteRequest has no env field and secrets must not reach a command line Drops the dead E2BExecutionResult.images field (populated, never consumed). * improvement(sandbox): select the provider by SANDBOX_PROVIDER env var Replaces the boolean sandbox-provider-daytona feature flag with a SANDBOX_PROVIDER env var naming the provider ('e2b' default, or 'daytona'). A boolean doesn't scale to a third adapter; a keyed registry does. - PROVIDERS is a Record<SandboxProviderId, SandboxProvider>, so adding an adapter is one entry plus one id-union member — an unhandled provider is a compile error, not a runtime surprise - resolveProvider() reads env synchronously and throws on an unknown value (fail fast) instead of an async feature-flag lookup - drops the sandbox-provider-daytona flag and SANDBOX_PROVIDER_DAYTONA fallback Verified end-to-end: a Python function block through the running app routes to Daytona (Creating Daytona sandbox, kind: code) with SANDBOX_PROVIDER=daytona. * fix(sandbox): gate remote execution by provider availability, not E2B Addresses the review round on #5860. - Availability was gated on isE2bEnabled / isE2BDocEnabled, so a Daytona-only deployment (E2B_ENABLED unset) had its Python/shell/JS-with-imports and doc paths rejected before the provider-neutral sandbox call could run. Replace both with provider-aware flags (isRemoteSandboxEnabled / isDocSandboxEnabled) derived from the selected SANDBOX_PROVIDER's own credentials + image. E2B behavior is unchanged (the E2B branch mirrors the old definitions exactly). - Make the function-block gate error messages provider-neutral. - Daytona's streaming runCommand (Pi) returned empty stdout/stderr and delivered output only via callbacks, so the Pi cloud flow — which parses markers from stdout and formats errors from stderr — saw nothing. Accumulate the streamed chunks and return them while still forwarding to the callbacks. Renames the env-flag exports (and the @sim/testing mock) to match. Adds a conformance test that the streamed Pi output lands in stdout/stderr. * fix(sandbox): resolve SANDBOX_PROVIDER case-insensitively Addresses the round-2 review on #5860. env-flags lowercased SANDBOX_PROVIDER for the availability gate, but resolveProvider looked up the raw value in a lowercase-keyed map — so 'Daytona' passed the gate then threw Unknown SANDBOX_PROVIDER at create. resolveProvider now normalizes casing identically. * fix(sandbox): use getErrorMessage in build/verify scripts check:utils flagged the inline `error instanceof Error ? error.message : ...` pattern in the two new scripts. Use getErrorMessage from @sim/utils/errors, matching the repo convention the check enforces. * fix(sandbox): fall back to stdout for Daytona failure text Daytona merges both streams into stdout and returns an empty stderr, but the shell-error, base64-export, and URL-mount error builders read only result.stderr — so Daytona failures surfaced a generic 'Process exited with code N' / 'base64 failed' / 'curl exited N' instead of the real command output that the API and agents rely on. Fall back to stdout before the generic message (provider-agnostic: E2B still populates stderr). Strengthens the shell-error conformance test to assert the real output surfaces. * fix(sandbox): enforce timeout on Daytona streaming; drop leftover E2B copy - Daytona's streaming path (Pi) started the command with runAsync:true and then awaited getSessionCommandLogs with no bound, so a hung command never timed out the way E2B's commands.run({ timeoutMs }) does. Race the log stream against the timeout; on expiry return exit 124 with the accumulated output, and the finally's deleteSession terminates the still-running command. - Two user-facing strings still named E2B after the provider-neutral rename (the isolated-vm sandboxPath remediation and the disabled-xlsx message). Made both provider-neutral. Adds a streaming-timeout conformance test. * fix(sandbox): handle orphaned stream promise + preserve error detail Two regressions from the previous timeout fix: - When the timeout won the race, the abandoned getSessionCommandLogs promise would reject on deleteSession with no handler (unhandledRejection). Attach a .catch that records the error and yields an 'error' outcome, so a late rejection is always handled. - The streaming catch dropped the thrown error, so failures before any chunks (env write, executeSessionCommand, missing cmdId) surfaced as empty output. Fall back to getErrorMessage(error) when nothing streamed. Adds conformance tests for the stream-reject and start-throw paths.
1 parent 3796e9d commit 96c67e9

38 files changed

Lines changed: 2103 additions & 947 deletions

apps/sim/app/api/function/execute/route.test.ts

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { NextRequest } from 'next/server'
1414
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
1515

1616
const {
17-
mockExecuteInE2B,
17+
mockExecuteInSandbox,
1818
mockExecuteInIsolatedVM,
1919
mockFetchWorkspaceFileBuffer,
2020
mockGetWorkspaceFile,
@@ -24,7 +24,7 @@ const {
2424
mockValidateWorkspaceFileWriteTarget,
2525
mockWriteWorkspaceFileByPath,
2626
} = vi.hoisted(() => ({
27-
mockExecuteInE2B: vi.fn(),
27+
mockExecuteInSandbox: vi.fn(),
2828
mockExecuteInIsolatedVM: vi.fn(),
2929
mockFetchWorkspaceFileBuffer: vi.fn(),
3030
mockGetWorkspaceFile: vi.fn(),
@@ -39,9 +39,9 @@ vi.mock('@/lib/execution/isolated-vm', () => ({
3939
executeInIsolatedVM: mockExecuteInIsolatedVM,
4040
}))
4141

42-
vi.mock('@/lib/execution/e2b', () => ({
43-
executeInE2B: mockExecuteInE2B,
44-
executeShellInE2B: vi.fn(),
42+
vi.mock('@/lib/execution/remote-sandbox', () => ({
43+
executeInSandbox: mockExecuteInSandbox,
44+
executeShellInSandbox: vi.fn(),
4545
SIM_RESULT_PREFIX: '__SIM_RESULT__=',
4646
}))
4747

@@ -113,7 +113,7 @@ afterAll(resetEnvFlagsMock)
113113
describe('Function Execute API Route', () => {
114114
beforeEach(() => {
115115
vi.clearAllMocks()
116-
envFlagsMock.isE2bEnabled = false
116+
envFlagsMock.isRemoteSandboxEnabled = false
117117

118118
hybridAuthMockFns.mockCheckInternalAuth.mockResolvedValue({
119119
success: true,
@@ -125,7 +125,7 @@ describe('Function Execute API Route', () => {
125125
mockUploadFile.mockImplementation(async ({ customKey }) => ({ key: customKey }))
126126
clearLargeValueCacheForTests()
127127

128-
mockExecuteInE2B.mockResolvedValue({
128+
mockExecuteInSandbox.mockResolvedValue({
129129
result: 'e2b success',
130130
stdout: 'e2b output',
131131
sandboxId: 'test-sandbox-id',
@@ -351,8 +351,8 @@ describe('Function Execute API Route', () => {
351351
})
352352

353353
it('exports multiple declared sandbox output files', async () => {
354-
envFlagsMock.isE2bEnabled = true
355-
mockExecuteInE2B.mockResolvedValueOnce({
354+
envFlagsMock.isRemoteSandboxEnabled = true
355+
mockExecuteInSandbox.mockResolvedValueOnce({
356356
result: 'done',
357357
stdout: 'ok',
358358
sandboxId: 'sandbox-123',
@@ -389,7 +389,7 @@ describe('Function Execute API Route', () => {
389389

390390
expect(response.status).toBe(200)
391391
expect(data.success).toBe(true)
392-
expect(mockExecuteInE2B).toHaveBeenCalledWith(
392+
expect(mockExecuteInSandbox).toHaveBeenCalledWith(
393393
expect.objectContaining({
394394
outputSandboxPaths: ['/home/user/chart.png', '/home/user/summary.json'],
395395
})
@@ -419,8 +419,8 @@ describe('Function Execute API Route', () => {
419419
})
420420

421421
it('prevalidates all sandbox output destinations before writing any files', async () => {
422-
envFlagsMock.isE2bEnabled = true
423-
mockExecuteInE2B.mockResolvedValueOnce({
422+
envFlagsMock.isRemoteSandboxEnabled = true
423+
mockExecuteInSandbox.mockResolvedValueOnce({
424424
result: 'done',
425425
stdout: 'ok',
426426
sandboxId: 'sandbox-123',
@@ -463,8 +463,8 @@ describe('Function Execute API Route', () => {
463463
})
464464

465465
it('rejects duplicate sandbox output destinations before writing files', async () => {
466-
envFlagsMock.isE2bEnabled = true
467-
mockExecuteInE2B.mockResolvedValueOnce({
466+
envFlagsMock.isRemoteSandboxEnabled = true
467+
mockExecuteInSandbox.mockResolvedValueOnce({
468468
result: 'done',
469469
stdout: 'ok',
470470
sandboxId: 'sandbox-123',
@@ -508,8 +508,8 @@ describe('Function Execute API Route', () => {
508508
})
509509

510510
it('returns a targeted error when a declared sandbox output is missing', async () => {
511-
envFlagsMock.isE2bEnabled = true
512-
mockExecuteInE2B.mockResolvedValueOnce({
511+
envFlagsMock.isRemoteSandboxEnabled = true
512+
mockExecuteInSandbox.mockResolvedValueOnce({
513513
result: 'done',
514514
stdout: 'ok',
515515
sandboxId: 'sandbox-123',
@@ -541,7 +541,7 @@ describe('Function Execute API Route', () => {
541541
})
542542

543543
it('rejects sandboxPath outputs when the call would run in isolated-vm (E2B enabled, JS without imports)', async () => {
544-
envFlagsMock.isE2bEnabled = true
544+
envFlagsMock.isRemoteSandboxEnabled = true
545545

546546
const req = createMockRequest('POST', {
547547
code: 'return "content"',
@@ -565,7 +565,7 @@ describe('Function Execute API Route', () => {
565565
expect(data.success).toBe(false)
566566
expect(data.error).toContain('no sandbox filesystem')
567567
expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled()
568-
expect(mockExecuteInE2B).not.toHaveBeenCalled()
568+
expect(mockExecuteInSandbox).not.toHaveBeenCalled()
569569
expect(mockWriteWorkspaceFileByPath).not.toHaveBeenCalled()
570570
})
571571

@@ -582,16 +582,16 @@ describe('Function Execute API Route', () => {
582582

583583
expect(response.status).toBe(422)
584584
expect(data.success).toBe(false)
585-
// E2B is disabled in this test, so the remediation must name that cause
586-
// instead of suggesting python (which would also fail without E2B).
587-
expect(data.error).toContain('E2B is not enabled')
585+
// No remote sandbox is enabled in this test, so the remediation must name
586+
// that cause instead of suggesting python (which would also fail without one).
587+
expect(data.error).toContain('No remote code sandbox is enabled')
588588
expect(mockExecuteInIsolatedVM).not.toHaveBeenCalled()
589589
})
590590

591591
it('flags an overwrite export whose bytes are identical to the current file content as unchanged', async () => {
592-
envFlagsMock.isE2bEnabled = true
592+
envFlagsMock.isRemoteSandboxEnabled = true
593593
const staleContent = '# doc\nunchanged mounted content\n'
594-
mockExecuteInE2B.mockResolvedValueOnce({
594+
mockExecuteInSandbox.mockResolvedValueOnce({
595595
result: 'done',
596596
stdout: 'ok',
597597
sandboxId: 'sandbox-123',
@@ -636,9 +636,9 @@ describe('Function Execute API Route', () => {
636636
})
637637

638638
it('reports size, previousSize, and sha256 receipts on a successful overwrite export', async () => {
639-
envFlagsMock.isE2bEnabled = true
639+
envFlagsMock.isRemoteSandboxEnabled = true
640640
const newContent = '# doc\nnew content\n'
641-
mockExecuteInE2B.mockResolvedValueOnce({
641+
mockExecuteInSandbox.mockResolvedValueOnce({
642642
result: 'done',
643643
stdout: 'ok',
644644
sandboxId: 'sandbox-123',
@@ -682,7 +682,7 @@ describe('Function Execute API Route', () => {
682682
expect(data.output.result.message).toContain('sha256:')
683683
// The python wrapper prints the marker with a leading \n so it always
684684
// starts a fresh line even after non-newline-terminated user output.
685-
const e2bCode = mockExecuteInE2B.mock.calls[0][0].code as string
685+
const e2bCode = mockExecuteInSandbox.mock.calls[0][0].code as string
686686
expect(e2bCode).toContain("print('\\n__SIM_RESULT__=' + json.dumps(__sim_result__))")
687687
})
688688

@@ -727,7 +727,7 @@ describe('Function Execute API Route', () => {
727727
})
728728

729729
it('rejects large refs in runtimes without ref-native helpers', async () => {
730-
envFlagsMock.isE2bEnabled = true
730+
envFlagsMock.isRemoteSandboxEnabled = true
731731
const req = createMockRequest('POST', {
732732
code: 'echo "$__blockRef_0"',
733733
language: 'shell',

apps/sim/app/api/function/execute/route.ts

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ import {
1616
validateWorkspaceFileWriteTarget,
1717
writeWorkspaceFileByPath,
1818
} from '@/lib/copilot/vfs/resource-writer'
19-
import { isE2bEnabled } from '@/lib/core/config/env-flags'
19+
import { isRemoteSandboxEnabled } from '@/lib/core/config/env-flags'
2020
import { generateRequestId } from '@/lib/core/utils/request'
2121
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
22-
import { executeInE2B, executeShellInE2B, SIM_RESULT_PREFIX } from '@/lib/execution/e2b'
2322
import { executeInIsolatedVM, type IsolatedVMBrokerHandler } from '@/lib/execution/isolated-vm'
2423
import { CodeLanguage, DEFAULT_CODE_LANGUAGE, isValidCodeLanguage } from '@/lib/execution/languages'
2524
import { recordMaterializedAccessKeys } from '@/lib/execution/payloads/access-keys'
@@ -36,6 +35,11 @@ import {
3635
} from '@/lib/execution/payloads/materialization.server'
3736
import { compactExecutionPayload } from '@/lib/execution/payloads/serializer'
3837
import { materializeLargeValueRef } from '@/lib/execution/payloads/store'
38+
import {
39+
executeInSandbox,
40+
executeShellInSandbox,
41+
SIM_RESULT_PREFIX,
42+
} from '@/lib/execution/remote-sandbox'
3943
import { isExecutionResourceLimitError } from '@/lib/execution/resource-errors'
4044
import {
4145
fetchWorkspaceFileBuffer,
@@ -1509,9 +1513,9 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
15091513
}
15101514

15111515
if (lang === CodeLanguage.Shell) {
1512-
if (!isE2bEnabled) {
1516+
if (!isRemoteSandboxEnabled) {
15131517
throw new Error(
1514-
'Shell execution requires E2B to be enabled. Please contact your administrator to enable E2B.'
1518+
'Shell execution requires a remote code sandbox to be enabled. Please contact your administrator to enable it.'
15151519
)
15161520
}
15171521

@@ -1524,7 +1528,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
15241528
}
15251529

15261530
logger.info(`[${requestId}] E2B shell execution`, {
1527-
enabled: isE2bEnabled,
1531+
enabled: isRemoteSandboxEnabled,
15281532
hasApiKey: Boolean(process.env.E2B_API_KEY),
15291533
envVarCount: Object.keys(shellEnvs).length,
15301534
})
@@ -1537,7 +1541,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
15371541
error: shellError,
15381542
exportedFileContent,
15391543
exportedFiles,
1540-
} = await executeShellInE2B({
1544+
} = await executeShellInSandbox({
15411545
code: resolvedCode,
15421546
envs: shellEnvs,
15431547
timeoutMs: timeout,
@@ -1589,41 +1593,44 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
15891593
)
15901594
}
15911595

1592-
if (lang === CodeLanguage.Python && !isE2bEnabled) {
1596+
if (lang === CodeLanguage.Python && !isRemoteSandboxEnabled) {
15931597
throw new Error(
1594-
'Python execution requires E2B to be enabled. Please contact your administrator to enable E2B, or use JavaScript instead.'
1598+
'Python execution requires a remote code sandbox to be enabled. Please contact your administrator to enable it, or use JavaScript instead.'
15951599
)
15961600
}
15971601

1598-
if (lang === CodeLanguage.JavaScript && hasImports && !isE2bEnabled) {
1602+
if (lang === CodeLanguage.JavaScript && hasImports && !isRemoteSandboxEnabled) {
15991603
throw new Error(
1600-
'JavaScript code with import statements requires E2B to be enabled. Please remove the import statements, or contact your administrator to enable E2B.'
1604+
'JavaScript code with import statements requires a remote code sandbox to be enabled. Please remove the import statements, or contact your administrator to enable it.'
16011605
)
16021606
}
16031607

1604-
const useE2B =
1605-
isE2bEnabled &&
1608+
const useRemoteSandbox =
1609+
isRemoteSandboxEnabled &&
16061610
!isCustomTool &&
16071611
(lang === CodeLanguage.Python || (lang === CodeLanguage.JavaScript && hasImports))
16081612

1609-
if (useE2B && containsLargeValueRef(contextVariables)) {
1613+
if (useRemoteSandbox && containsLargeValueRef(contextVariables)) {
16101614
throw new Error(
1611-
'Large execution values require the JavaScript isolated-vm runtime. Remove imports, select a nested field, or read the value in a JavaScript function without E2B.'
1615+
'Large execution values require the JavaScript isolated-vm runtime. Remove imports, select a nested field, or read the value in a JavaScript function without a remote sandbox.'
16121616
)
16131617
}
16141618

1615-
// Sandbox file mounts and sandboxPath exports only exist in the E2B
1616-
// runtime; isolated-vm has no filesystem. Silently dropping a declared
1619+
// Sandbox file mounts and sandboxPath exports only exist in the remote
1620+
// sandbox runtime; isolated-vm has no filesystem. Silently dropping a declared
16171621
// sandbox input/output here produced "export succeeded" responses with
16181622
// zero bytes written, so refuse the call instead. The remediation depends
16191623
// on WHY this call runs in isolated-vm — "switch to python" is a dead end
1620-
// when E2B is disabled or the call is a custom tool.
1621-
if (!useE2B && (outputSandboxPaths.length > 0 || outputSandboxPath || _sandboxFiles?.length)) {
1622-
const remediation = !isE2bEnabled
1623-
? "E2B is not enabled on this deployment, so there is no sandbox filesystem for any language. Pass input data via params and return output as the code's return value with outputs.files[].path (no sandboxPath)."
1624+
// when no remote sandbox is enabled or the call is a custom tool.
1625+
if (
1626+
!useRemoteSandbox &&
1627+
(outputSandboxPaths.length > 0 || outputSandboxPath || _sandboxFiles?.length)
1628+
) {
1629+
const remediation = !isRemoteSandboxEnabled
1630+
? "No remote code sandbox is enabled on this deployment, so there is no sandbox filesystem for any language. Pass input data via params and return output as the code's return value with outputs.files[].path (no sandboxPath)."
16241631
: isCustomTool
16251632
? "custom tools always run in the isolated JavaScript VM, which has no sandbox filesystem. Pass input data via params and return output as the code's return value."
1626-
: 'plain JavaScript runs in the isolated VM, which has no sandbox filesystem. Use language "python" so the code runs in the E2B sandbox, or drop sandboxPath and return the file content as the code\'s return value with outputs.files[].path.'
1633+
: 'plain JavaScript runs in the isolated VM, which has no sandbox filesystem. Use language "python" so the code runs in the remote sandbox, or drop sandboxPath and return the file content as the code\'s return value with outputs.files[].path.'
16271634
return functionJsonResponse(
16281635
{
16291636
success: false,
@@ -1635,9 +1642,9 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
16351642
)
16361643
}
16371644

1638-
if (useE2B) {
1645+
if (useRemoteSandbox) {
16391646
logger.info(`[${requestId}] E2B status`, {
1640-
enabled: isE2bEnabled,
1647+
enabled: isRemoteSandboxEnabled,
16411648
hasApiKey: Boolean(process.env.E2B_API_KEY),
16421649
language: lang,
16431650
})
@@ -1693,7 +1700,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
16931700
error: e2bError,
16941701
exportedFileContent,
16951702
exportedFiles,
1696-
} = await executeInE2B({
1703+
} = await executeInSandbox({
16971704
code: codeForE2B,
16981705
language: CodeLanguage.JavaScript,
16991706
timeoutMs: timeout,
@@ -1781,7 +1788,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
17811788
error: e2bError,
17821789
exportedFileContent,
17831790
exportedFiles,
1784-
} = await executeInE2B({
1791+
} = await executeInSandbox({
17851792
code: codeForE2B,
17861793
language: CodeLanguage.Python,
17871794
timeoutMs: timeout,

apps/sim/app/api/mothership/execute/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { buildSelectedMcpToolSchemas, buildTaggedMcpToolSchemas } from '@/lib/co
1818
import { runHeadlessCopilotLifecycle } from '@/lib/copilot/request/lifecycle/headless'
1919
import { requestExplicitStreamAbort } from '@/lib/copilot/request/session/explicit-abort'
2020
import type { StreamEvent } from '@/lib/copilot/request/types'
21-
import { isE2BDocEnabled } from '@/lib/core/config/env-flags'
21+
import { isDocSandboxEnabled } from '@/lib/core/config/env-flags'
2222
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
2323
import {
2424
assertActiveWorkspaceAccess,
@@ -199,7 +199,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => {
199199
messageId,
200200
isHosted: true,
201201
workspaceContext,
202-
...(isE2BDocEnabled ? { docCompiler: 'python' } : {}),
202+
...(isDocSandboxEnabled ? { docCompiler: 'python' } : {}),
203203
...(userMetadata ? { userMetadata } : {}),
204204
...(fileAttachments && fileAttachments.length > 0 ? { fileAttachments } : {}),
205205
...(agentContexts.length > 0 || mothershipTools.length > 0

apps/sim/app/api/workspaces/[id]/files/[fileId]/compiled-check/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { parseRequest } from '@/lib/api/server'
66
import { getSession } from '@/lib/auth'
77
import { getE2BDocFormat } from '@/lib/copilot/tools/server/files/doc-compile'
88
import { runE2BCompiledCheck } from '@/lib/copilot/tools/server/files/doc-recalc'
9-
import { isE2BDocEnabled } from '@/lib/core/config/env-flags'
9+
import { isDocSandboxEnabled } from '@/lib/core/config/env-flags'
1010
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1111
import { BINARY_DOC_TASKS, MAX_DOCUMENT_PREVIEW_CODE_BYTES } from '@/lib/execution/constants'
1212
import { runSandboxTask, SandboxUserCodeError } from '@/lib/execution/sandbox/run-task'
@@ -57,7 +57,7 @@ export const GET = withRouteHandler(
5757
// In the E2B regime ALL four formats compile in the doc sandbox (Node for
5858
// pptx/docx, Python for pdf/xlsx). Gate on the flag (not the stored MIME) so
5959
// a stale file can't trigger an E2B compile when the sandbox is disabled.
60-
const e2bFmt = isE2BDocEnabled ? await getE2BDocFormat(fileRecord.name) : null
60+
const e2bFmt = isDocSandboxEnabled ? await getE2BDocFormat(fileRecord.name) : null
6161
const taskId = BINARY_DOC_TASKS[ext]
6262
const isMermaidFile = ext === 'mmd' || ext === 'mermaid'
6363
if (!e2bFmt && !taskId && !isMermaidFile) {

apps/sim/executor/handlers/pi/cloud-backend.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const { mockRun, mockReadFile, mockWriteFile, mockExecuteTool, mockProviderEnvVa
1313
})
1414
)
1515

16-
vi.mock('@/lib/execution/e2b', () => ({
16+
vi.mock('@/lib/execution/remote-sandbox', () => ({
1717
withPiSandbox: (fn: (runner: unknown) => unknown) =>
1818
fn({ run: mockRun, readFile: mockReadFile, writeFile: mockWriteFile }),
1919
}))

apps/sim/executor/handlers/pi/cloud-backend.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import { createLogger } from '@sim/logger'
1616
import { generateShortId } from '@sim/utils/id'
1717
import { truncate } from '@sim/utils/string'
18-
import { withPiSandbox } from '@/lib/execution/e2b'
18+
import { withPiSandbox } from '@/lib/execution/remote-sandbox'
1919
import type { PiBackendRun, PiCloudRunParams } from '@/executor/handlers/pi/backend'
2020
import {
2121
CLONE_TIMEOUT_MS,

apps/sim/executor/handlers/pi/cloud-review-backend.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const mockModelRuntime = {
5858
removeRuntimeApiKey: mockRemoveRuntimeApiKey,
5959
}
6060

61-
vi.mock('@/lib/execution/e2b', () => ({
61+
vi.mock('@/lib/execution/remote-sandbox', () => ({
6262
withPiSandbox: (fn: (runner: unknown) => unknown) =>
6363
fn({ run: mockRun, writeFile: mockWriteFile }),
6464
}))

apps/sim/executor/handlers/pi/cloud-review-backend.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { tmpdir } from 'node:os'
99
import { join } from 'node:path'
1010
import { createLogger } from '@sim/logger'
1111
import { truncate } from '@sim/utils/string'
12-
import { withPiSandbox } from '@/lib/execution/e2b'
12+
import { withPiSandbox } from '@/lib/execution/remote-sandbox'
1313
import type { PiBackendRun, PiCloudReviewRunParams } from '@/executor/handlers/pi/backend'
1414
import {
1515
CLOUD_REVIEW_TOOL_NAMES,

apps/sim/executor/handlers/pi/cloud-review-tools.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { join } from 'node:path'
88
import { promisify } from 'node:util'
99
import * as sdk from '@earendil-works/pi-coding-agent'
1010
import { beforeEach, describe, expect, it, vi } from 'vitest'
11-
import type { PiSandboxRunner } from '@/lib/execution/e2b'
11+
import type { PiSandboxRunner } from '@/lib/execution/remote-sandbox'
1212
import {
1313
CLOUD_REVIEW_TOOL_NAMES,
1414
createCloudReviewTools,

0 commit comments

Comments
 (0)