$ -weight: 500;">pip -weight: 500;">install tensorlake
tl login # or TENSORLAKE_API_KEY env var
-weight: 500;">pip -weight: 500;">install tensorlake
tl login # or TENSORLAKE_API_KEY env var
-weight: 500;">pip -weight: 500;">install tensorlake
tl login # or TENSORLAKE_API_KEY env var
from tensorlake.sandbox import Sandbox sandbox = Sandbox.create( name="research-agent", cpus=2.0, memory_mb=4096, secret_names=["OPENAI_API_KEY"], image="tensorlake/ubuntu-vnc",
)
from tensorlake.sandbox import Sandbox sandbox = Sandbox.create( name="research-agent", cpus=2.0, memory_mb=4096, secret_names=["OPENAI_API_KEY"], image="tensorlake/ubuntu-vnc",
)
from tensorlake.sandbox import Sandbox sandbox = Sandbox.create( name="research-agent", cpus=2.0, memory_mb=4096, secret_names=["OPENAI_API_KEY"], image="tensorlake/ubuntu-vnc",
)
sandbox.run("-weight: 500;">pip", ["-weight: 500;">install", "playwright"])
sandbox.run("playwright", ["-weight: 500;">install", "chromium"])
sandbox.run("-weight: 500;">pip", ["-weight: 500;">install", "playwright"])
sandbox.run("playwright", ["-weight: 500;">install", "chromium"])
sandbox.run("-weight: 500;">pip", ["-weight: 500;">install", "playwright"])
sandbox.run("playwright", ["-weight: 500;">install", "chromium"])
Sandbox creation: ~800ms (named sandbox, first time)
Sandbox resume: ~400ms (from suspended state)
LLM call (GPT-4o): 2,000-4,000ms (per step, dominates everything)
Browser screenshot: ~300ms (capture + transfer)
Page load in sandbox: 1,000-2,000ms (varies by site)
File read/write: <50ms (block-based storage)
Sandbox suspend: ~200ms
Sandbox creation: ~800ms (named sandbox, first time)
Sandbox resume: ~400ms (from suspended state)
LLM call (GPT-4o): 2,000-4,000ms (per step, dominates everything)
Browser screenshot: ~300ms (capture + transfer)
Page load in sandbox: 1,000-2,000ms (varies by site)
File read/write: <50ms (block-based storage)
Sandbox suspend: ~200ms
Sandbox creation: ~800ms (named sandbox, first time)
Sandbox resume: ~400ms (from suspended state)
LLM call (GPT-4o): 2,000-4,000ms (per step, dominates everything)
Browser screenshot: ~300ms (capture + transfer)
Page load in sandbox: 1,000-2,000ms (varies by site)
File read/write: <50ms (block-based storage)
Sandbox suspend: ~200ms
with sandbox.connect_desktop(password="tensorlake") as desktop: png_bytes = desktop.screenshot() desktop.move_mouse(640, 400) desktop.click() desktop.type_text("pinecone.io") desktop.press("Return")
with sandbox.connect_desktop(password="tensorlake") as desktop: png_bytes = desktop.screenshot() desktop.move_mouse(640, 400) desktop.click() desktop.type_text("pinecone.io") desktop.press("Return")
with sandbox.connect_desktop(password="tensorlake") as desktop: png_bytes = desktop.screenshot() desktop.move_mouse(640, 400) desktop.click() desktop.type_text("pinecone.io") desktop.press("Return")
result = sandbox.run( "python", ["-c", """
import asyncio
from playwright.async_api import async_playwright async def get_pricing(): async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page() await page.goto("https://pinecone.io/pricing") pricing_text = await page.inner_text(".pricing-section") print(pricing_text) await browser.close() asyncio.run(get_pricing())
"""]
)
result = sandbox.run( "python", ["-c", """
import asyncio
from playwright.async_api import async_playwright async def get_pricing(): async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page() await page.goto("https://pinecone.io/pricing") pricing_text = await page.inner_text(".pricing-section") print(pricing_text) await browser.close() asyncio.run(get_pricing())
"""]
)
result = sandbox.run( "python", ["-c", """
import asyncio
from playwright.async_api import async_playwright async def get_pricing(): async with async_playwright() as p: browser = await p.chromium.launch() page = await browser.new_page() await page.goto("https://pinecone.io/pricing") pricing_text = await page.inner_text(".pricing-section") print(pricing_text) await browser.close() asyncio.run(get_pricing())
"""]
)
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
# After each step, before suspending:
sandbox.write_file( "/workspace/state.json", json.dumps({ "pinecone_pricing": pinecone_data, "weaviate_started": True, "next_url": "https://weaviate.io/pricing" }).encode()
)
sandbox.suspend() # On next invocation, from any process:
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
state = json.loads(bytes(sandbox.read_file("/workspace/state.json")))
# picks up from state["next_url"]
# After each step, before suspending:
sandbox.write_file( "/workspace/state.json", json.dumps({ "pinecone_pricing": pinecone_data, "weaviate_started": True, "next_url": "https://weaviate.io/pricing" }).encode()
)
sandbox.suspend() # On next invocation, from any process:
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
state = json.loads(bytes(sandbox.read_file("/workspace/state.json")))
# picks up from state["next_url"]
# After each step, before suspending:
sandbox.write_file( "/workspace/state.json", json.dumps({ "pinecone_pricing": pinecone_data, "weaviate_started": True, "next_url": "https://weaviate.io/pricing" }).encode()
)
sandbox.suspend() # On next invocation, from any process:
sandbox = Sandbox.connect("research-agent")
sandbox.resume()
state = json.loads(bytes(sandbox.read_file("/workspace/state.json")))
# picks up from state["next_url"]
from tensorlake.sandbox import Sandbox
from concurrent.futures import ThreadPoolExecutor def research_competitor(name, url): sandbox = Sandbox.create( name=f"research-{name}", cpus=1.0, memory_mb=2048, secret_names=["OPENAI_API_KEY"], image="ubuntu-vnc", ) # ... agent logic ... result = sandbox.read_file("/workspace/report.json") sandbox.terminate() return result competitors = [ ("pinecone", "pinecone.io/pricing"), ("weaviate", "weaviate.io/pricing"), ("qdrant", "qdrant.tech/pricing"),
] with ThreadPoolExecutor(max_workers=5) as executor: reports = list(executor.map(lambda c: research_competitor(*c), competitors))
from tensorlake.sandbox import Sandbox
from concurrent.futures import ThreadPoolExecutor def research_competitor(name, url): sandbox = Sandbox.create( name=f"research-{name}", cpus=1.0, memory_mb=2048, secret_names=["OPENAI_API_KEY"], image="ubuntu-vnc", ) # ... agent logic ... result = sandbox.read_file("/workspace/report.json") sandbox.terminate() return result competitors = [ ("pinecone", "pinecone.io/pricing"), ("weaviate", "weaviate.io/pricing"), ("qdrant", "qdrant.tech/pricing"),
] with ThreadPoolExecutor(max_workers=5) as executor: reports = list(executor.map(lambda c: research_competitor(*c), competitors))
from tensorlake.sandbox import Sandbox
from concurrent.futures import ThreadPoolExecutor def research_competitor(name, url): sandbox = Sandbox.create( name=f"research-{name}", cpus=1.0, memory_mb=2048, secret_names=["OPENAI_API_KEY"], image="ubuntu-vnc", ) # ... agent logic ... result = sandbox.read_file("/workspace/report.json") sandbox.terminate() return result competitors = [ ("pinecone", "pinecone.io/pricing"), ("weaviate", "weaviate.io/pricing"), ("qdrant", "qdrant.tech/pricing"),
] with ThreadPoolExecutor(max_workers=5) as executor: reports = list(executor.map(lambda c: research_competitor(*c), competitors))
# Filesystem snapshot (default)
snapshot = sandbox.checkpoint() try: agent.navigate_to_pricing_page()
except Exception: # Restore filesystem state into a new sandbox sandbox = Sandbox.create(snapshot_id=snapshot.snapshot_id)
# Filesystem snapshot (default)
snapshot = sandbox.checkpoint() try: agent.navigate_to_pricing_page()
except Exception: # Restore filesystem state into a new sandbox sandbox = Sandbox.create(snapshot_id=snapshot.snapshot_id)
# Filesystem snapshot (default)
snapshot = sandbox.checkpoint() try: agent.navigate_to_pricing_page()
except Exception: # Restore filesystem state into a new sandbox sandbox = Sandbox.create(snapshot_id=snapshot.snapshot_id)
┌─────────────────────────────────────────────┐
│ Your Agent │
│ (LLM + tool calling logic) │
└──────────────────┬──────────────────────────┘ │ tool calls
┌──────────────────▼──────────────────────────┐
│ Tensorlake Sandbox │
│ ┌──────────────────────────────────────┐ │
│ │ State Layer: /workspace filesystem │ │
│ │ state.json, research_notes.json │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Execution Layer: processes, scripts │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Computer Use: VNC, screenshots, mouse│ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Your Agent │
│ (LLM + tool calling logic) │
└──────────────────┬──────────────────────────┘ │ tool calls
┌──────────────────▼──────────────────────────┐
│ Tensorlake Sandbox │
│ ┌──────────────────────────────────────┐ │
│ │ State Layer: /workspace filesystem │ │
│ │ state.json, research_notes.json │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Execution Layer: processes, scripts │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Computer Use: VNC, screenshots, mouse│ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
┌─────────────────────────────────────────────┐
│ Your Agent │
│ (LLM + tool calling logic) │
└──────────────────┬──────────────────────────┘ │ tool calls
┌──────────────────▼──────────────────────────┐
│ Tensorlake Sandbox │
│ ┌──────────────────────────────────────┐ │
│ │ State Layer: /workspace filesystem │ │
│ │ state.json, research_notes.json │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Execution Layer: processes, scripts │ │
│ └──────────────────────────────────────┘ │
│ ┌──────────────────────────────────────┐ │
│ │ Computer Use: VNC, screenshots, mouse│ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
from tensorlake.sandbox import SandboxClient client = SandboxClient() for sb in client.list(): print(sb.sandbox_id, sb.-weight: 500;">status)
from tensorlake.sandbox import SandboxClient client = SandboxClient() for sb in client.list(): print(sb.sandbox_id, sb.-weight: 500;">status)
from tensorlake.sandbox import SandboxClient client = SandboxClient() for sb in client.list(): print(sb.sandbox_id, sb.-weight: 500;">status)
report_bytes = sandbox.read_file("/workspace/comparison_report.md")
print(bytes(report_bytes).decode("utf-8"))
report_bytes = sandbox.read_file("/workspace/comparison_report.md")
print(bytes(report_bytes).decode("utf-8"))
report_bytes = sandbox.read_file("/workspace/comparison_report.md")
print(bytes(report_bytes).decode("utf-8")) - Both use Firecracker microVMs. E2B markets sub-200ms cold starts; community reports put real-world p50 closer to 400-600ms. Tensorlake named sandbox creation was ~800ms in my testing.
- E2B has added snapshot and pause-resume in recent releases. The statefulness gap is narrower than a year ago. Tensorlake's suspend/resume preserves the full running VM state, including open processes, browser sessions, all in under a second. E2B's memory snapshot support is still described as early-stage.
- Tensorlake claims 1.6-1.9x faster filesystem I/O on their own benchmarks. Self-reported. For an independent reference: Tensorlake recently ranked top 2 across all three categories in the ComputeSDK sandbox benchmarks.
- Neither provides DOM-level element selection at the SDK layer. - Modal uses gVisor rather than Firecracker, designed around stateless function execution. Stateful long-running agents work but need more setup. Cold starts are around 1-1.5 seconds per their docs. - Stagehand has DOM-level selectors (CSS, XPath, natural language) via locator(). For pure browser automation, this is a real ergonomic advantage.
- Tensorlake gives you a full VM. Code execution, file management, package installs, and browser use in the same environment. If that combination is what you need, the full VM model is worth the coordinate complexity.
- Browser automation only? Stagehand is the more focused tool.