SDK sandbox provisioning: built-in providers, docs restructure, and quickstart overhaul

- Add built-in sandbox providers (local, docker, e2b, daytona, vercel, cloudflare) to the TypeScript SDK so users import directly instead of passing client instances
- Restructure docs: rename architecture to orchestration-architecture, add new architecture page for server overview, improve getting started flow
- Rewrite quickstart to be TypeScript-first with provider CodeGroup and custom provider accordion
- Update all examples to use new provider APIs
- Update persist drivers and foundry for new SDK surface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Nathan Flurry 2026-03-15 12:39:05 -07:00
parent 3426cbc6ec
commit 6a42f06342
53 changed files with 1689 additions and 667 deletions

View file

@ -9,10 +9,10 @@
"dependencies": {
"@sandbox-agent/example-shared": "workspace:*",
"dockerode": "latest",
"get-port": "latest",
"sandbox-agent": "workspace:*"
},
"devDependencies": {
"@types/dockerode": "latest",
"@types/node": "latest",
"tsx": "latest",
"typescript": "latest",

View file

@ -1,68 +1,40 @@
import Docker from "dockerode";
import fs from "node:fs";
import path from "node:path";
import { SandboxAgent } from "sandbox-agent";
import { detectAgent, buildInspectorUrl } from "@sandbox-agent/example-shared";
import { docker } from "sandbox-agent/docker";
import { detectAgent } from "@sandbox-agent/example-shared";
import { FULL_IMAGE } from "@sandbox-agent/example-shared/docker";
const IMAGE = FULL_IMAGE;
const PORT = 3000;
const agent = detectAgent();
const codexAuthPath = process.env.HOME ? path.join(process.env.HOME, ".codex", "auth.json") : null;
const bindMounts = codexAuthPath && fs.existsSync(codexAuthPath) ? [`${codexAuthPath}:/home/sandbox/.codex/auth.json:ro`] : [];
const env = [
process.env.ANTHROPIC_API_KEY ? `ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}` : "",
process.env.OPENAI_API_KEY ? `OPENAI_API_KEY=${process.env.OPENAI_API_KEY}` : "",
process.env.CODEX_API_KEY ? `CODEX_API_KEY=${process.env.CODEX_API_KEY}` : "",
].filter(Boolean);
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
// Pull image if needed
try {
await docker.getImage(IMAGE).inspect();
} catch {
console.log(`Pulling ${IMAGE}...`);
await new Promise<void>((resolve, reject) => {
docker.pull(IMAGE, (err: Error | null, stream: NodeJS.ReadableStream) => {
if (err) return reject(err);
docker.modem.followProgress(stream, (err: Error | null) => (err ? reject(err) : resolve()));
});
});
}
console.log("Starting container...");
const container = await docker.createContainer({
Image: IMAGE,
Cmd: ["server", "--no-token", "--host", "0.0.0.0", "--port", `${PORT}`],
Env: [
process.env.ANTHROPIC_API_KEY ? `ANTHROPIC_API_KEY=${process.env.ANTHROPIC_API_KEY}` : "",
process.env.OPENAI_API_KEY ? `OPENAI_API_KEY=${process.env.OPENAI_API_KEY}` : "",
process.env.CODEX_API_KEY ? `CODEX_API_KEY=${process.env.CODEX_API_KEY}` : "",
].filter(Boolean),
ExposedPorts: { [`${PORT}/tcp`]: {} },
HostConfig: {
AutoRemove: true,
PortBindings: { [`${PORT}/tcp`]: [{ HostPort: `${PORT}` }] },
Binds: bindMounts,
},
const client = await SandboxAgent.start({
sandbox: docker({
image: FULL_IMAGE,
env,
binds: bindMounts,
}),
});
await container.start();
const baseUrl = `http://127.0.0.1:${PORT}`;
console.log(`UI: ${client.inspectorUrl}`);
const client = await SandboxAgent.connect({ baseUrl });
const session = await client.createSession({ agent, sessionInit: { cwd: "/home/sandbox", mcpServers: [] } });
const sessionId = session.id;
const session = await client.createSession({
agent: detectAgent(),
cwd: "/home/sandbox",
});
console.log(` UI: ${buildInspectorUrl({ baseUrl, sessionId })}`);
console.log(" Press Ctrl+C to stop.");
session.onEvent((event) => {
console.log(`[${event.sender}]`, JSON.stringify(event.payload));
});
const keepAlive = setInterval(() => {}, 60_000);
const cleanup = async () => {
clearInterval(keepAlive);
try {
await container.stop({ t: 5 });
} catch {}
try {
await container.remove({ force: true });
} catch {}
session.prompt([{ type: "text", text: "Say hello from Docker in one sentence." }]);
process.once("SIGINT", async () => {
await client.destroySandbox();
process.exit(0);
};
process.once("SIGINT", cleanup);
process.once("SIGTERM", cleanup);
});