Versions: @tanstack/ai-sandbox-daytona 0.2.1, @tanstack/ai-sandbox 0.3.0, @daytona/sdk v0.191.0.
Summary
Daytona stops an idle sandbox after 15 minutes by default. The adapter does not set autoStopInterval. A stopped sandbox keeps its filesystem, and one SDK call (sandbox.start()) starts it again. resume() does not make that call. Thus lifecycle: { reuse: 'thread' } operates only when runs occur less than 15 minutes apart.
Mechanism
- Run 1 creates a sandbox, completes bootstrap, and ends.
destroyOnComplete: false keeps the sandbox.
- The sandbox is idle for 15 minutes. Daytona stops it. The filesystem stays.
- Run 2 starts in the same thread.
ensure() calls provider.resume (packages/ai-sandbox/src/sandbox.ts).
DaytonaProvider.resume (packages/ai-sandbox-daytona/src/provider.ts) only calls daytona.get(id) and wraps the result. daytona.get is a metadata request. It is successful for stopped and archived sandboxes. It does not start the sandbox (sdk-typescript/src/Daytona.ts in daytona/clients, tag v0.191.0).
ensure() accepts each non-null handle as a started sandbox. The fallback to snapshot restore or to a new sandbox occurs only when resume returns null.
- The first
executeCommand goes to the sandbox toolbox. The toolbox returns HTTP 400 with a message that ends with Is the Sandbox started?. The run ends with this error.
lifecycle.keepAlive: '30m' gives no protection. Per docs/sandbox/lifecycle.md, no code reads keepAlive. The adapter sends no idle limit to Daytona.
Expected
docs/sandbox/providers.md says that Daytona has resume-by-id. A resumed handle must accept commands.
Impact
Each reuse: 'thread' deployment on Daytona gets this error when two runs are more than 15 minutes apart. For human chat threads, this is the usual case, not a rare case. Durable-run takeover with resume-by-id has the same defect. The user sees an HTTP 400 error in the run, not a cold start.
Fix direction
- In
resume(), read sandbox.state.
- If the state is
stopped or archived, call await sandbox.start() before you wrap the handle.
- You can also add
autoStopInterval to DaytonaSandboxConfig (minutes; 0 = off).
With the state check, Daytona becomes a durable resume-by-id provider. The filesystem already stays through a stop. This also gives #1029 a Daytona path with no new code.
Versions:
@tanstack/ai-sandbox-daytona0.2.1,@tanstack/ai-sandbox0.3.0,@daytona/sdkv0.191.0.Summary
Daytona stops an idle sandbox after 15 minutes by default. The adapter does not set
autoStopInterval. A stopped sandbox keeps its filesystem, and one SDK call (sandbox.start()) starts it again.resume()does not make that call. Thuslifecycle: { reuse: 'thread' }operates only when runs occur less than 15 minutes apart.Mechanism
destroyOnComplete: falsekeeps the sandbox.ensure()callsprovider.resume(packages/ai-sandbox/src/sandbox.ts).DaytonaProvider.resume(packages/ai-sandbox-daytona/src/provider.ts) only callsdaytona.get(id)and wraps the result.daytona.getis a metadata request. It is successful for stopped and archived sandboxes. It does not start the sandbox (sdk-typescript/src/Daytona.tsin daytona/clients, tag v0.191.0).ensure()accepts each non-null handle as a started sandbox. The fallback to snapshot restore or to a new sandbox occurs only whenresumereturnsnull.executeCommandgoes to the sandbox toolbox. The toolbox returns HTTP 400 with a message that ends withIs the Sandbox started?. The run ends with this error.lifecycle.keepAlive: '30m'gives no protection. Perdocs/sandbox/lifecycle.md, no code readskeepAlive. The adapter sends no idle limit to Daytona.Expected
docs/sandbox/providers.mdsays that Daytona has resume-by-id. A resumed handle must accept commands.Impact
Each
reuse: 'thread'deployment on Daytona gets this error when two runs are more than 15 minutes apart. For human chat threads, this is the usual case, not a rare case. Durable-run takeover with resume-by-id has the same defect. The user sees an HTTP 400 error in the run, not a cold start.Fix direction
resume(), readsandbox.state.stoppedorarchived, callawait sandbox.start()before you wrap the handle.autoStopIntervaltoDaytonaSandboxConfig(minutes;0= off).With the state check, Daytona becomes a durable resume-by-id provider. The filesystem already stays through a stop. This also gives #1029 a Daytona path with no new code.