feat(providers): simplify modal to use published base image

The `-full` base image already includes sandbox-agent and all agents
pre-installed. Remove redundant apt-get, install script, and
install-agent dockerfile commands from the Modal provider.

Also allow overriding the default image via SANDBOX_AGENT_IMAGE env var
across all providers for testing with different published versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nathan Flurry 2026-03-17 16:54:20 -07:00
parent 4e76038a0d
commit 524f40ec02
2 changed files with 6 additions and 12 deletions

View file

@ -1,11 +1,10 @@
import { ModalClient, type Image, type SandboxCreateParams } from "modal"; import { ModalClient, type Image, type SandboxCreateParams } from "modal";
import type { SandboxProvider } from "./types.ts"; import type { SandboxProvider } from "./types.ts";
import { DEFAULT_AGENTS, SANDBOX_AGENT_INSTALL_SCRIPT } from "./shared.ts"; import { DEFAULT_SANDBOX_AGENT_IMAGE } from "./shared.ts";
const DEFAULT_AGENT_PORT = 3000; const DEFAULT_AGENT_PORT = 3000;
const DEFAULT_APP_NAME = "sandbox-agent"; const DEFAULT_APP_NAME = "sandbox-agent";
const DEFAULT_MEMORY_MIB = 2048; const DEFAULT_MEMORY_MIB = 2048;
const DEFAULT_BASE_IMAGE = "node:22-slim";
type ModalCreateOverrides = Omit<Partial<SandboxCreateParams>, "secrets" | "encryptedPorts"> & { type ModalCreateOverrides = Omit<Partial<SandboxCreateParams>, "secrets" | "encryptedPorts"> & {
secrets?: Record<string, string>; secrets?: Record<string, string>;
@ -33,17 +32,12 @@ export function modal(options: ModalProviderOptions = {}): SandboxProvider {
async create(): Promise<string> { async create(): Promise<string> {
const createOpts = await resolveCreateOptions(options.create); const createOpts = await resolveCreateOptions(options.create);
const appName = createOpts.appName ?? DEFAULT_APP_NAME; const appName = createOpts.appName ?? DEFAULT_APP_NAME;
const baseImage = options.image ?? DEFAULT_BASE_IMAGE; const baseImage = options.image ?? DEFAULT_SANDBOX_AGENT_IMAGE;
const app = await client.apps.fromName(appName, { createIfMissing: true }); const app = await client.apps.fromName(appName, { createIfMissing: true });
// Pre-install sandbox-agent and agents in the image so they are cached // The default `-full` base image already includes sandbox-agent and all
// across sandbox creates and don't need to be installed at runtime. // agents pre-installed, so no additional dockerfile commands are needed.
const installAgentCmds = DEFAULT_AGENTS.map((agent) => `RUN sandbox-agent install-agent ${agent}`); const image = typeof baseImage === "string" ? client.images.fromRegistry(baseImage) : baseImage;
const image = (typeof baseImage === "string" ? client.images.fromRegistry(baseImage) : baseImage).dockerfileCommands([
"RUN apt-get update && apt-get install -y curl ca-certificates && rm -rf /var/lib/apt/lists/*",
`RUN curl -fsSL ${SANDBOX_AGENT_INSTALL_SCRIPT} | sh`,
...installAgentCmds,
]);
const envVars = createOpts.secrets ?? {}; const envVars = createOpts.secrets ?? {};
const secrets = Object.keys(envVars).length > 0 ? [await client.secrets.fromObject(envVars)] : []; const secrets = Object.keys(envVars).length > 0 ? [await client.secrets.fromObject(envVars)] : [];

View file

@ -1,4 +1,4 @@
export const DEFAULT_SANDBOX_AGENT_IMAGE = "rivetdev/sandbox-agent:0.5.0-rc.1-full"; export const DEFAULT_SANDBOX_AGENT_IMAGE = process.env.SANDBOX_AGENT_IMAGE ?? "rivetdev/sandbox-agent:0.5.0-rc.1-full";
export const SANDBOX_AGENT_INSTALL_SCRIPT = "https://releases.rivet.dev/sandbox-agent/0.3.x/install.sh"; export const SANDBOX_AGENT_INSTALL_SCRIPT = "https://releases.rivet.dev/sandbox-agent/0.3.x/install.sh";
export const DEFAULT_AGENTS = ["claude", "codex"] as const; export const DEFAULT_AGENTS = ["claude", "codex"] as const;