You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@cloudflare/think/tools/sandbox currently exports createSandboxTools(), but the implementation is intentionally a no-op: it logs a warning once and returns {}.
That means the blog/docs-level execution ladder says Think can wire in Cloudflare Sandbox as Tier 4, but the package export does not yet provide any usable tools.
This issue tracks turning createSandboxTools() into a real integration with the Cloudflare Sandbox SDK, or narrowing/removing the public promise until the integration exists.
Current behavior
Current implementation in packages/think/src/tools/sandbox.ts:
exportfunctioncreateSandboxTools(_binding?: unknown,_options?: CreateSandboxToolsOptions): ToolSet{if(!warned){warned=true;console.warn("[@cloudflare/think] createSandboxTools is not yet implemented. "+"No tools will be registered.");}return{};}
The export exists in packages/think/package.json as @cloudflare/think/tools/sandbox, so users can import and spread it, but they get no tools.
Why this matters
Project Think's execution ladder is meant to be additive:
Tier 0: Think Workspace / @cloudflare/shell
Tier 1: Dynamic Worker / codemode execution
Tier 2: npm/runtime dependency loading
Tier 3: browser automation
Tier 4: full Sandbox for OS-level toolchains, repos, test runners, compilers, and long-running processes
Tier 4 is the escape hatch for tasks that cannot fit in a Workers isolate: git clone, npm test, cargo build, real CLIs, shell scripts, code review bots, and heavyweight project work.
Right now Think has a named Sandbox tool export, but no actual Sandbox bridge. That creates a confusing gap for users and for the roadmap.
Sandbox SDK capabilities to target
The Sandbox SDK already exposes useful primitives:
getSandbox(env.Sandbox, id) to create/reuse a sandbox instance
exec() for command execution with complete stdout/stderr/exit code
execStream() for long-running commands with streamed output
startProcess() / process log streaming for services
Keep the first implementation boring and testable: command execution + file transfer.
Workspace sync question
The important design question is how Think's DO-local Workspace interacts with the Sandbox filesystem.
Possible approaches:
A. Explicit file transfer tools
The model calls read / find / grep against Think Workspace, then calls sandbox_write_file for files it wants in the Sandbox. After commands run, it calls sandbox_read_file to pull results back.
Pros: simple, no hidden sync, minimal API.
Cons: tedious for whole repos / many files.
B. Helper methods for push/pull workspace snapshots
Expose tools like:
sandbox_push_workspace({ paths, sandboxPath })
sandbox_pull_workspace({ sandboxPath, paths })
Pros: better UX for project work.
Cons: needs careful path filtering, binary handling, limits, and conflict behavior.
C. Git/Artifacts handoff
Use Git/Artifacts as the handoff boundary: Think commits workspace state to an Artifacts repo, Sandbox clones/mounts it, pushes results, and Think imports/reviews the diff.
Pros: clean versioned boundary, aligns with #1440.
Cons: larger integration; should not block the minimal createSandboxTools() milestone.
Recommendation: start with A, design B after using it, and keep C linked to #1440.
API shape questions
Should createSandboxTools() accept a Sandbox Durable Object namespace directly, or a factory function like (id) => getSandbox(binding, id)?
How should the sandbox id be chosen by default: Think agent name, chat/session id, caller-provided id, or a generated per-run id?
Should tools reuse a long-lived sandbox per Think agent/session, or create per-run sandboxes?
How should timeouts work, given Sandbox command timeout behavior does not necessarily kill the underlying process?
Should path access be restricted to /workspace by default?
Should network/proxy setup be part of createSandboxTools() or left to application code?
How do we surface preview URLs / running background processes without turning v1 into a full IDE API?
Security constraints
Do not pass durable secrets directly into sandbox commands by default.
Prefer Worker-side proxy patterns for external APIs so the sandbox gets short-lived scoped credentials, not real API keys.
Require explicit opt-in for network credentials, repo write tokens, or access to user data.
Default path access should be scoped, probably to /workspace.
Tool outputs must be truncated/structured to avoid blowing up model context.
Commands should have explicit timeouts and clear behavior for non-zero exit codes.
Avoid logging secrets in command strings, outputs, or chat history.
Relationship to existing Think tools
createExecuteTool() remains the default for small JavaScript programs in Dynamic Worker isolates.
createSandboxTools() is for full OS/toolchain work that cannot run in codemode: real shell commands, package managers, compilers, tests, CLI agents, and services.
Browser tools remain separate; Sandbox should not replace createBrowserTools().
Parent roadmap: #1439
Summary
@cloudflare/think/tools/sandboxcurrently exportscreateSandboxTools(), but the implementation is intentionally a no-op: it logs a warning once and returns{}.That means the blog/docs-level execution ladder says Think can wire in Cloudflare Sandbox as Tier 4, but the package export does not yet provide any usable tools.
This issue tracks turning
createSandboxTools()into a real integration with the Cloudflare Sandbox SDK, or narrowing/removing the public promise until the integration exists.Current behavior
Current implementation in
packages/think/src/tools/sandbox.ts:The export exists in
packages/think/package.jsonas@cloudflare/think/tools/sandbox, so users can import and spread it, but they get no tools.Why this matters
Project Think's execution ladder is meant to be additive:
@cloudflare/shellTier 4 is the escape hatch for tasks that cannot fit in a Workers isolate:
git clone,npm test,cargo build, real CLIs, shell scripts, code review bots, and heavyweight project work.Right now Think has a named Sandbox tool export, but no actual Sandbox bridge. That creates a confusing gap for users and for the roadmap.
Sandbox SDK capabilities to target
The Sandbox SDK already exposes useful primitives:
getSandbox(env.Sandbox, id)to create/reuse a sandbox instanceexec()for command execution with complete stdout/stderr/exit codeexecStream()for long-running commands with streamed outputstartProcess()/ process log streaming for servicesreadFile,writeFile,mkdir,exists, delete/move/renameFor Think v1, we should probably start with a small subset instead of exposing the whole SDK.
Proposed first milestone
Implement a minimal
createSandboxTools(binding, options)that exposes a conservative tool set for Think agents:sandbox_execcommand, optionalsandboxId, optionalcwd, optionaltimeout.stdout,stderr,exitCode,success, maybe truncated output metadata.sandbox_write_file/workspaceor another allowlisted path.path,content, optional encoding.sandbox_read_filepath, optional encoding / max bytes.Optional later:
sandbox_exec_streamOptional later:
sandbox_expose_port/ preview URL helpers.Keep the first implementation boring and testable: command execution + file transfer.
Workspace sync question
The important design question is how Think's DO-local Workspace interacts with the Sandbox filesystem.
Possible approaches:
A. Explicit file transfer tools
The model calls
read/find/grepagainst Think Workspace, then callssandbox_write_filefor files it wants in the Sandbox. After commands run, it callssandbox_read_fileto pull results back.Pros: simple, no hidden sync, minimal API.
Cons: tedious for whole repos / many files.
B. Helper methods for push/pull workspace snapshots
Expose tools like:
sandbox_push_workspace({ paths, sandboxPath })sandbox_pull_workspace({ sandboxPath, paths })Pros: better UX for project work.
Cons: needs careful path filtering, binary handling, limits, and conflict behavior.
C. Git/Artifacts handoff
Use Git/Artifacts as the handoff boundary: Think commits workspace state to an Artifacts repo, Sandbox clones/mounts it, pushes results, and Think imports/reviews the diff.
Pros: clean versioned boundary, aligns with #1440.
Cons: larger integration; should not block the minimal
createSandboxTools()milestone.Recommendation: start with A, design B after using it, and keep C linked to #1440.
API shape questions
createSandboxTools()accept a Sandbox Durable Object namespace directly, or a factory function like(id) => getSandbox(binding, id)?/workspaceby default?createSandboxTools()or left to application code?Security constraints
/workspace.Relationship to existing Think tools
createExecuteTool()remains the default for small JavaScript programs in Dynamic Worker isolates.createSandboxTools()is for full OS/toolchain work that cannot run in codemode: real shell commands, package managers, compilers, tests, CLI agents, and services.createBrowserTools().Acceptance criteria
createSandboxTools()returns at least one real AI SDK tool instead of{}when passed a valid Sandbox binding/factory.createExecuteTool()versuscreateSandboxTools().Nice-to-have follow-ups
Useful files
packages/think/src/tools/sandbox.tspackages/think/src/tools/execute.tsdocs/think/tools.mdexamples/assistant/src/server.tsexperimental/gadgets-sandbox/README.mdReferences