Edge Developer Platform
  • Pages
    • Product Introduction
    • Quick Start
      • Agent Development
      • Importing a Git Repository
      • Starting From a Template
      • Direct Upload
      • Start with AI
    • Framework Guide
      • Agent
      • Frontends
        • Vite
        • React
        • Vue
        • Hugo
        • Other Frameworks
      • Backends
      • Full-stack
        • Next.js
        • Nuxt
        • Astro
        • React Router
        • SvelteKit
        • TanStack Start
        • Vike
      • Custom 404 Page
    • Project Guide
      • Project Management
      • edgeone.json
      • Configuring Cache
      • Building Output Configuration
      • Domain Management
        • Overview
        • Custom Domain
        • HTTPS Configuration
          • Overview
          • Apply for Free Certificate
          • Using Managed SSL Certificate
        • Configure DNS CNAME Record
      • Error Codes
    • Build Guide
    • Deployment Guide
      • Overview
      • Create Deploys
      • Manage Deploys
      • Deploy Button
      • Using Github Actions
      • Using Gitlab CI/CD
      • Using CNB Plugin
      • Using IDE PlugIn
      • Using CodeBuddy IDE
    • Enterprise Solutions
      • Vibe Coding
      • Platform and Multi-Tenancy
      • Internal Applications
    • Observability
      • Overview
      • Metric Analysis
      • Log Analysis
    • Functions
      • Overview
      • Edge Functions
      • Cloud Functions
        • Overview
        • Node.js
        • Python
        • Go
    • Agents
      • Overview
      • Quick Start
      • Conversation Management
      • Observability
      • Sandbox Tool
        • Overview
        • Using the Agent Framework
        • Sandbox Atomic API
        • Network Search Tool
      • Agent Authentication
    • Models
      • Overview
      • Models and Vendors
        • Overview
        • Using the Zhuque Model
        • Using Vendor Keys
          • OpenAI
          • Anthropic
          • Google AI Studio
          • DeepSeek
          • MiniMax
          • Hunyuan
          • Zhipu
          • MoonShot AI
      • FAQs
    • Storage
      • Overview
      • KV
      • Blob
    • Middleware
    • AI-Native Development
      • Plugin
      • Skills
      • MCP
    • Copilot
      • Overview
      • Quick Start
    • API Token
    • EdgeOne CLI
    • Message Notification
    • Integration Guide
      • AI
        • Makers Models Integration
        • Large Models for Images Integration
      • Database
        • Supabase Integration
        • Pages KV Integration
      • Ecommerce
        • Shopify Integration
        • WooCommerce Integration
      • Payment
        • Stripe Integration
        • Integrating Paddle
      • CMS
        • WordPress Integration
        • Contentful Integration
        • Sanity Integration
        • Payload Integration
      • Authentication
        • Supabase Integration
        • Clerk Integration
    • Best Practices
      • Adding an AI Chat Assistant to a Website
      • AI Dialogue Deployment: Deploy Project with One Sentence Using Skill
      • Building Agent Applications Quickly with Makers Agents
      • Building an Ecommerce Platform with Shopify
      • Building a SaaS Site Using Supabase and Stripe
      • Building a Company Brand Site Quickly
      • How to Quickly Build a Blog Site
      • Quick Launch via Login-Free Deployment in WorkBuddy
    • Migration Guides
      • Migrating from Vercel to EdgeOne Makers
      • Migrating from Cloudflare Pages to EdgeOne Makers
      • Migrating from Netlify to EdgeOne Makers
    • Troubleshooting
    • FAQs
    • Limits
    • Pricing
    • Contact Us
    • Release Notes

Overview

The sandbox tools built into Makers Agents run on isolated Tencent Cloud instances underneath. These instances are dedicated to handling the "side effects" of Agent execution, such as running commands, reading and writing files, controlling browsers, and executing code. This gives LLMs the real ability to "get their hands dirty" rather than merely outputting text.

Two-Tier API

The platform packages the same sandbox instance into two layers of APIs and exposes them on the context: one layer for the LLM to invoke as tools, and the other for developers to use directly.
Perspective
Field
Target User
Granularity
LLM Perspective
context.tools.*
Tool list for LLM (wrapped as native objects by framework)
Flattened into atomic tools  to allow on-demand expansion of the call scope.
Developer Perspective
context.sandbox.*
Sandbox atomic APIs directly invoked by developer code
Organized by module: commands / files / browser / runCode top-level methods
The two layers of APIs share the same underlying sandbox instance. The built-in tools in context.tools that require sandbox capabilities are implemented by directly calling context.sandbox.*, eliminating the need for two separate sets of logic.

Instance Lifecycle

Level
Description
Instance Ownership
One conversation corresponds to one instance, and it is hosted based on the conversation_id dimension.
Creation Timing
Lazy loading — invoked by the adaptation layer when the sandbox tool is accessed for the first time.
Cross-Request Reuse
If the sandbox instance is not terminated, sandbox tool requests with the same conversation_id are routed to the same instance.
Lifecycle Upper Limit
Controlled by the sandbox.timeout in edgeone.json, and automatically recycled when the time point is reached.
Isolation
Sandbox instances of different conversations are physically isolated.

Project Persistence and Recovery

Sandbox instances are temporary runtime resources. When an instance expires, is reclaimed, or after kill() is called, there is no guarantee that unsaved sandbox files and runtime state can be recovered.
If the application needs to continue using the project after subsequent requests, page refreshes, or sandbox instance recreation, explicitly call the following API in the developer code:
context.sandbox.persist({ path }): Saves the project content at the specified path as a persistent checkpoint for the current project.
context.sandbox.restore({ path }): Attempts to restore the persisted project content to the specified path.
Persisted data is written to the __sandbox Blob storage retained by the current project. Archived bytes do not pass through conversation messages or conversation metadata. Persisted source code counts toward the Blob storage space and quota of the current project. Applications do not need to directly access or manage the __sandbox storage.

persist(options)

Save the content in the specified project directory as a persistent checkpoint for the current project. The archive size limit is 25 MiB. Dependencies, build outputs, version control, and cache directories are excluded by default. You can also use exclude to add directory names to exclude.

Parameters

Parameter
Type
Required
Description
path
string
Yes
Non-root project directory that needs to be persisted.
exclude
string[]
No
Additional directory names to exclude. By default, node_modules, .next, .git, dist, build, out, coverage, .cache, .turbo, .vite, .parcel-cache, __pycache__, .venv, venv, and .edgeone are excluded.
timeout
number
No
Timeout for the entire persistence operation, in seconds. Defaults to 180 seconds. Must be a positive integer.
Returned results:
{
size: number;
sha256: string;
etag: string;
persistedAt: string;
}

restore(options)

Attempts to restore the persisted project content to a specified non-root project directory. Before restoration, the archive is downloaded and verified. After a successful restoration, the target directory is replaced with the project content from the checkpoint.

Parameters

Parameter
Type
Required
Description
path
string
Yes
Non-root target directory for restoring project content.
timeout
number
No
Timeout for the entire restore operation, in seconds. Defaults to 180 seconds. Must be a positive integer.
Returns when no checkpoint is available:
{
restored: false;
reason: 'not_found';
}
Returned on successful restoration:
{
restored: true;
size: number;
sha256: string;
etag: string;
persistedAt: string;
}

TypeScript Example

const projectPath = 'projects/<conversation_id>/app';

// When initializing the workspace, first attempt to restore an existing checkpoint.
const restored = await context.sandbox.restore({
path: projectPath,
timeout: 180,
});

if (!restored.restored) {
// If no checkpoint is available, initialize a new project workspace.
await context.sandbox.files.makeDir(projectPath);
// Initialize project files.
}

// Save the latest checkpoint after project files are modified.
const persisted = await context.sandbox.persist({
path: projectPath,
timeout: 180,
});
console.log(persisted.size, persisted.persistedAt);
The Node SDK uses object parameters, while the Python SDK uses keyword parameters. For example:
await sandbox.persist(
path='/home/user/project',
exclude=['tmp'],
timeout=180,
)
restored = await sandbox.restore(
path='/home/user/project',
timeout=180,
)
It is recommended to call restore() when the project workspace is initialized, and to wait for persist() to complete after important files are modified, after tasks are stopped, or before the sandbox instance is released.
persist() and restore() only process the project content in the specified directory. Running processes, browser state, temporary environment state, and preview URLs are not guaranteed to be persisted. After restoring a project, if a preview is required, restart the service and obtain a new preview URL. Archived content does not pass through Agent Runtime memory. Storage and request traffic are counted toward the Blob quota of the current project.

Instance Control

The method is mounted at the top level of context.sandbox to manage the lifecycle of the sandbox instance itself and its external exposure.
Methodology
Purpose
getHost(port)
Obtain the external access address of the sandbox instance.
envdAccessToken
Obtain the data plane access token.
getInfo()
Obtain current sandbox information (instanceId, expiresAt, and so on)
extendTimeout(seconds)
Extend the lifetime of the current sandbox instance; returns { instanceId, expiresAt, message? }.
kill()
Terminate the sandbox instance.

getHost(port) / get_host(port)

Obtain the externally accessible address of a specific port on the sandbox instance. This address is used to expose the server started within the sandbox to browsers or external callers.
Parameter
Parameter
Type
Required
Description
port
number / int
Yes
The port number that listens within the sandbox
Return Value
An external address in the format https://<port>-<instance>.sandbox.example.com.
TS Example:
// Start a vite dev server in the sandbox, then return its access address to the frontend.
await context.sandbox.commands.run('nohup npx vite --port 5173 &', { timeout: 10 })
const previewUrl = context.sandbox.getHost(5173)
return Response.json({ previewUrl })
Python example:
await ctx.sandbox.commands.run('nohup python -m http.server 8000 &', timeout=10)
preview_url = ctx.sandbox.get_host(8000)
return {'preview_url': preview_url}

envdAccessToken / envd_access_token

Obtain the access token for the sandbox instance's data plane.
Return Value
envd token
TS Example:
const token = context.sandbox.envdAccessToken
Python example:
token = ctx.sandbox.envd_access_token

getInfo() / get_info()

Obtain the sandbox metadata cached for the current session, such as the sandbox instance ID and expiration time.
Return Value
SandboxInfo
interface SandboxInfo {
instanceId: string
sandboxToken: string
sandboxDomain?: string
envdVersion?: string
expiresAt: string // An ISO time string returned by the backend acquire/update operation.
}
@dataclass
class SandboxInfo:
instance_id: str
sandbox_token: str
expires_at: str
sandbox_domain: Optional[str] = None
envd_version: Optional[str] = None
TS Example:
const info = context.sandbox.getInfo()
console.log(info.instanceId, info.expiresAt)
const remainingMs = new Date(info.expiresAt).getTime() - Date.now()
if (remainingMs < 60_000) {
await context.sandbox.extendTimeout(600)
}
Python example:
info = ctx.sandbox.get_info()
print(info.instance_id, info.expires_at)

extendTimeout(seconds) / extend_timeout(seconds)

Initiate a renewal request for the current sandbox instance. The actual effective duration is determined by the backend's response. If the number of seconds you request exceeds the remaining renewable window allowed by the backend, the backend truncates the request and informs you of the actual renewal time. The SDK then synchronously updates the local cache using the returned expiresAt / expires_at.
Parameter
Parameter
Type
Required
Description
seconds
number / int
Yes
The renewal duration in seconds, which must be a positive integer.
Return Value
UpdateResponse
interface UpdateResponse {
instanceId: string
expiresAt: string // The actual new expiration time confirmed by the backend.
message?: string // Returned only when the renewal is truncated by the backend, for example, "extended to max lifetime".
}
Python: dict, with fields instance_id / expires_at / message? (snake_case).
TS Example
await context.sandbox.commands.run('echo init', { timeout: 300 })
const renewed = await context.sandbox.extendTimeout(600)
console.log('new expiresAt:', renewed.expiresAt)
Python Example
await ctx.sandbox.commands.run('echo init', timeout=300)
renewed = await ctx.sandbox.extend_timeout(600)
print('new expires_at:', renewed['expires_at'])

kill()

Terminate the current sandbox instance proactively.
context.sandbox.kill()
When should you call kill? Call it when a one-time script finishes, or when you confirm that the entire conversation has ended and you want to immediately release the sandbox instance quota.

Error Code Descriptions

Error Code
Description
SANDBOX_LIMIT_EXCEEDED
Concurrent instance quantity / Total memory-hour quota / Maximum runtime per instance exceeded
SANDBOX_INVALID_PARAMETER
Parameter validation failed, for example, due to missing conversation_id or authorization Token.
SANDBOX_AUTHORIZATION_EXPIRED
Authorization Token invalid/expired
SANDBOX_FAILED_OPERATION
Sandbox service operation failed (such as due to rate limiting/timeout)
SANDBOX_NETWORK_ERROR
Sandbox service network abnormal.
SANDBOX_INSTANCE_UNAVAILABLE
Sandbox instance does not exist or has expired.
SANDBOX_NETWORK_ERROR
Data plane runtime client dependency missing or failed to create.
SANDBOX_UNKNOWN_ERROR
Fallback error code. For error details, refer to the message field.
If you encounter the above issues and cannot resolve them, you can join our Discord server EdgeOne to seek technical support.

FAQ

Q:browser_screenshot returns what? base64 or a URL?
A: Returns { base64Image } (PNG base64). It does not return a URL, nor does it save the file within the sandbox. If you need to display it on the frontend / persist it, you can upload it to object storage to obtain a URL.
Q:browser_fetch What is the difference between browser_fetch and a direct HTTP request?
A: browser_fetch uses a real Chromium browser for navigation (CDP + Playwright) and can retrieve page metadata and HTML after JavaScript rendering. A regular HTTP fetch can only retrieve the raw response. For scenarios requiring lightweight API scraping, you can use curl within commands.
Q: Can the timeout for the sandbox instance be adjusted to 10 hours?
A: Currently, the maximum runtime for a free edition sandbox instance is 1 hour. If you need to extend the instance runtime, you can submit a ticket to request it.
Q: Can only a subset of tools be made available to the LLM?
A: Yes. context.tools.all() is the complete set. As needed, you can use context.tools.files() / context.tools.browser() to obtain tool groups, or use context.tools.get(name) to assemble a custom subset.