Repository navigation
ctx.getSandbox(environment) drops custom provider session methods at runtime, but its type still exposes them #5020
Description
Summary
With a custom provider from defineSandboxProvider(), ctx.getSandbox(environment) is typed to return the provider's session type, RuntimeSandboxSessionFor<Session>. At runtime it returns eve's fixed handle from buildSandboxSession(), which only forwards the standard SandboxSession surface (plus setNetworkPolicy when one is given). Any other method the provider's session implements is undefined on the returned object, so calling it throws TypeError: … is not a function.
TypeScript accepts the call, so nothing flags it until runtime.
Versions
- Reproduced on eve 0.77.0.
- Checked the published builds of 0.78.0, 0.79.2 and 0.80.1 (latest):
buildSandboxSessionindist/src/execution/sandbox/session.jsis unchanged, and so aredist/src/shared/sandbox-provider.d.tsandsandbox-session.d.ts.
Minimal repro
// agent/sandbox.ts
import { defineSandbox, type SandboxSession } from "eve/sandbox";
import { defineSandboxProvider } from "eve/sandbox/provider";
interface AcmeSandboxSession extends SandboxSession {
exists(path: string): Promise<boolean>; // provider-specific method
}
export const AcmeSandbox = defineSandboxProvider<
undefined, // environment options
undefined, // open options
{ templateId: string }, // prepared artifact
{ remoteId: string }, // session state
AcmeSandboxSession // provider-specific session type
>({
name: "acme",
environment() {
return {
async prepare() { return { templateId: "t" }; },
async start() {
const sandbox = createAcmeSession(); // implements SandboxSession + exists()
return { handle: handleFor(sandbox), state: { remoteId: "r" } };
},
async resume() { return handleFor(createAcmeSession()); },
};
},
});
export const environment = AcmeSandbox.environment();
export default defineSandbox(() => environment.open());// agent/tools/check.ts
import { defineTool } from "eve/tools";
import { z } from "zod";
import { environment } from "../sandbox";
export default defineTool({
description: "Check whether a file exists.",
inputSchema: z.object({ path: z.string() }),
async execute({ path }, ctx) {
const sandbox = await ctx.getSandbox(environment); // typed as AcmeSandboxSession & { stop, delete }
return sandbox.exists(path); // compiles; at runtime: TypeError: sandbox.exists is not a function
},
});Expected
One of these:
ctx.getSandbox(environment)returns an object that exposes the provider session's own methods, as its type says; or- the return type matches what is actually forwarded, so the call fails to compile. The docs should then say custom-provider extras aren't reachable from tools, and how to reach them instead.
Actual
buildSandboxSession(e, setNetworkPolicy) builds a new object with only resolvePath, run, spawn, readFile, readBinaryFile, readTextFile, writeFile, writeBinaryFile, writeTextFile, removePath (and setNetworkPolicy). Everything else on e, the provider's session, is lost. Unit tests that call the provider session directly pass, so the gap only shows up once tools run inside eve.
Notes
- The sandbox docs ("Use the sandbox") say to "Pass the configured environment to preserve its specific session capabilities in authored runtime code", which suggests option 1 is intended. In practice that only holds for
setNetworkPolicyon the built-in providers. - Related, but not the same: Type the sandbox passed to environment prepare() with the environment session capabilities #3717 is about the types of
prepare()and ofDefaultSandbox. This issue is about a runtime gap for custom providers whose types already promise the methods. - Possible fixes:
- forward unknown members to the provider session, e.g. spread or proxy the provider session's own methods after the standard ones, so eve's wrappers still take precedence; or
- add an explicit hook to
defineSandboxProvider()for declaring extra session members to forward; or - narrow the type of
getSandbox(environment)for custom providers to the forwarded surface.
Workaround we're using
The provider keeps a per-process Map<eveSessionId, ProviderSession>, filled in start/resume and cleared in the handle's stop/delete/shutdown callbacks and in onSessionEnd. Tools first await ctx.getSandbox(environment), which makes eve start or resume the sandbox in this process, then look up the provider session by ctx.session.id to call the extra methods. It works, but it depends on eve's lifecycle ordering and duplicates state eve already holds.
Activity
test(eve): repro tool sandboxes dropping custom provider session methods
roboeve commentedon Oct 19, 2026
Confirmed on
origin/main: a tool'sctx.getSandbox(environment)loses methods a custom provider session defines on its class, sosandbox.exists(...)compiles but throwsTypeError: ... is not a function. Own-property methods survive, and hooks and channel events are not affected.Repro: #5021
Regressed in: not a recent regression (fails on every checked release back to
eve@0.65.0)fix(eve): keep custom provider session methods in tool sandboxes
roboeve commentedon Oct 19, 2026
Fix proposed in #5022, assigned to @ruiconti. This issue closes when it merges.