Skip to content

Commit 59327fe

Browse files
icecrasher321claude
andcommitted
fix(pi): share the sandbox sizing and lift E2B off the base default
The two Pi images had drifted on exactly the axis their shared module exists to prevent. Daytona asked for 4 CPU / 8 GB; the E2B template asked for nothing and inherited its base default of 2 vCPU / 512 MB. That is a 16x memory gap between the provider Pi normally runs on and the one it fails over to, so a failover could be OOM-killed doing work that had just succeeded. 512 MB is too small independently of the drift: the Pi CLI is a Node process holding an LLM context, running beside a clone of the user's repository, and Node is OOM-killed rather than degraded at that ceiling — which reaches the user as an opaque agent failure. CPU and memory now come from pi-sandbox-packages.ts alongside the package lists. Disk stays in the Daytona renderer: its 10 GB per-sandbox cap is a hard provider limit with no E2B equivalent, so it is the one dimension where the images legitimately differ. E2B fixes resources at template build time, so this takes effect only when build-pi-e2b-template.ts is re-run — nothing builds these images in CI. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1df7836 commit 59327fe

4 files changed

Lines changed: 55 additions & 5 deletions

File tree

apps/docs/content/docs/en/workflows/blocks/pi.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ Create PR runs in a sandbox image with the Pi CLI and git baked in.
194194

195195
1. **Enable sandbox execution.** On self-hosted Sim, set `E2B_ENABLED=true`, `E2B_API_KEY`, `E2B_PI_TEMPLATE_ID` (the Pi template id), and `NEXT_PUBLIC_E2B_ENABLED=true` (this reveals Create PR and Review Code in the UI). Build the template with `bun run apps/sim/scripts/build-pi-e2b-template.ts`. These modes stay hidden until `NEXT_PUBLIC_E2B_ENABLED` is set.
196196

197+
The template requests **4 vCPU and 8 GB of RAM** (within the per-build maximum on every E2B plan). Sizing is fixed when the template is built — E2B has no per-sandbox override — so changing it means rebuilding the template, not restarting Sim. Sandboxes are billed per second against the resources they are allocated, not the ones they use. Both numbers live in `apps/sim/scripts/pi-sandbox-packages.ts` and are shared with the Daytona snapshot so the failover image cannot drift from the primary.
198+
197199
Sim sizes each Pi sandbox to **the execution's own remaining time**, so a run never holds a sandbox longer than the platform would let it run. The ceiling when there is no deadline to narrow to is the longest execution any plan permits (90 minutes); E2B rejects a create above the session length its plan allows, which is 1 hour on Hobby and 24 hours on Professional. `PI_SANDBOX_LIFETIME_MS` may lower that ceiling but has a **31-minute minimum**; lower values are raised to the minimum. A run that outlives the sandbox loses its work before the push, and an orphaned sandbox — one whose Sim process died mid-run — bills until the lifetime expires, which is why that lifetime tracks the deadline. Babysit Mode uses a second sequential sandbox after the creation sandbox has been destroyed; it is billed while polling checks and reviews. Daytona remains unchanged because its auto-stop setting is inactivity-based rather than an absolute lifetime.
198200
2. **Bring your own model key.** Set the provider API key in the block's API Key field, or store it in **Settings → BYOK** when the provider supports workspace BYOK.
199201
3. **Create a GitHub token** with permission to clone, push, and open a PR:

apps/sim/scripts/build-pi-daytona-snapshot.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,29 @@ import {
3131
PI_NODE_MAJOR,
3232
PI_NODE_VERSION_ASSERT,
3333
PI_NPM,
34+
PI_SANDBOX_CPU_COUNT,
35+
PI_SANDBOX_MEMORY_GB,
3436
} from '@/scripts/pi-sandbox-packages'
3537

3638
/** Matches E2B's base: Debian 13 (trixie) with Python 3.13 installed to /usr/local. */
3739
const BASE_IMAGE = 'python:3.13-slim-trixie'
3840

3941
/**
40-
* `daytona-large` sizing. 10 GB is a HARD per-sandbox disk cap — the API rejects
41-
* anything larger ("Disk request 20GB exceeds maximum allowed per sandbox
42-
* (10GB)"), regardless of plan tier, and raising it requires contacting Daytona.
43-
* That is the binding constraint on how large a repo Pi can clone here.
42+
* CPU and memory come from the shared module so the two providers cannot drift
43+
* apart on sizing the way they already had — see {@link PI_SANDBOX_CPU_COUNT}.
44+
*
45+
* Disk stays local because it is not shareable: 10 GB is a HARD per-sandbox cap
46+
* here — the API rejects anything larger ("Disk request 20GB exceeds maximum
47+
* allowed per sandbox (10GB)"), regardless of plan tier, and raising it requires
48+
* contacting Daytona. E2B allows 20 GB, so this is the binding constraint on how
49+
* large a repo Pi can clone on the failover provider, and the one dimension where
50+
* the two images legitimately differ.
4451
*/
45-
const RESOURCES = { cpu: 4, memory: 8, disk: 10 } as const
52+
const RESOURCES = {
53+
cpu: PI_SANDBOX_CPU_COUNT,
54+
memory: PI_SANDBOX_MEMORY_GB,
55+
disk: 10,
56+
} as const
4657

4758
const APT_PREFIX = 'DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends'
4859

apps/sim/scripts/build-pi-e2b-template.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
PI_NODE_MAJOR,
2323
PI_NODE_VERSION_ASSERT,
2424
PI_NPM,
25+
PI_SANDBOX_CPU_COUNT,
26+
PI_SANDBOX_MEMORY_MB,
2527
} from '@/scripts/pi-sandbox-packages'
2628

2729
const DEFAULT_TEMPLATE_NAME = 'sim-pi'
@@ -51,9 +53,15 @@ async function main() {
5153
const skipCache = args.includes('--no-cache')
5254

5355
console.log(`Building Pi E2B template: ${templateName}`)
56+
console.log(`Resources: ${PI_SANDBOX_CPU_COUNT} vCPU / ${PI_SANDBOX_MEMORY_MB} MB`)
5457
console.log(skipCache ? 'Cache: disabled\n' : 'Cache: enabled\n')
5558

59+
// Resources are fixed at build time — E2B has no per-`Sandbox.create` override —
60+
// so this template's sizing applies to Create PR, Review Code, and Babysit
61+
// alike, and changing it means rebuilding rather than redeploying the app.
5662
const result = await Template.build(piTemplate, templateName, {
63+
cpuCount: PI_SANDBOX_CPU_COUNT,
64+
memoryMB: PI_SANDBOX_MEMORY_MB,
5765
onBuildLogs: defaultBuildLogger(),
5866
...(skipCache ? { skipCache: true } : {}),
5967
})

apps/sim/scripts/pi-sandbox-packages.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,32 @@ export const PI_NODE_VERSION_ASSERT =
5757
* only the Daytona image has to provide it explicitly.
5858
*/
5959
export const PI_REQUIRES_PYTHON3 = true
60+
61+
/**
62+
* vCPU and RAM for the Pi sandbox, shared for the same reason the package lists
63+
* are: the two providers had already drifted here. Daytona asked for 4 CPU / 8 GB
64+
* while the E2B template asked for nothing and inherited its base default of
65+
* 2 vCPU / 512 MB — a 16x memory gap between the provider Pi normally runs on and
66+
* the one it fails over to, which would surface as the agent being killed on E2B
67+
* for work that succeeded on Daytona.
68+
*
69+
* 512 MB is the real problem: the Pi CLI is a Node process holding an LLM
70+
* context, running beside a `git clone` of the user's repository, and Node has no
71+
* graceful behaviour at that ceiling — it is OOM-killed, which reaches the user
72+
* as an opaque agent failure rather than a diagnosable one.
73+
*
74+
* Both numbers are at E2B's Professional maximum (8 vCPU / 8192 MB per build,
75+
* 1 vCPU / 512 MB minimum). Sizing is per-second billed against allocated
76+
* resources rather than used ones, so this costs roughly 3x the previous E2B
77+
* default per sandbox-second. On the compute-bound phases that is close to
78+
* neutral — the work finishes proportionally sooner — but Babysit deliberately
79+
* idles between review polls, and idle seconds bill at the same rate. Lower
80+
* {@link PI_SANDBOX_CPU_COUNT} first if that idle time proves dominant: vCPU is
81+
* ~3x the hourly rate of a GB of RAM, and RAM is the dimension that prevents
82+
* hard failures.
83+
*/
84+
export const PI_SANDBOX_CPU_COUNT = 4
85+
86+
/** Kept in GB and MB because Daytona takes GB and E2B takes MB. */
87+
export const PI_SANDBOX_MEMORY_GB = 8
88+
export const PI_SANDBOX_MEMORY_MB = PI_SANDBOX_MEMORY_GB * 1024

0 commit comments

Comments
 (0)