Skip to main content
The problem: You want the agent to answer questions by running real code — computations, data transformations, script verification — without trusting LLM-hallucinated output and without bloating the context window with raw data. The solution: Expose a custom execute_code tool backed by a SandboxRuntime interface. The LLM writes a short self-contained script, passes it to the tool, and reads the actual output. The sandbox handles isolation — the SDK never runs code itself.

What the LLM does vs. what the sandbox does

LLMYour sandbox
Decide when to run codeExecute the script
Write a self-contained scriptEnforce resource limits
Read output and explain it to the userIsolate from host filesystem and network
Retry with a fixed script on non-zero exit_codeReturn stdout + stderr and exit code
The LLM never invents output — it always calls execute_code first. Example: Code Execution.

Tool pattern

type SandboxRuntime interface {
    Execute(ctx context.Context, language, code string) (ExecutionResult, error)
}

a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithTools(NewCodeTool(yourRuntime)),
)
Execute blocks until the sandbox returns ExecutionResult{Output, ExitCode}. The LLM reads output from the result and replies to the user.

Sandbox options

Implement SandboxRuntime once per environment. The example ships two; add more by following the same pattern:
SandboxUse caseActivate
Local os/execDevelopment, CI, trusted scriptsdefault (no env var)
DockerIsolated execution on your hostSANDBOX_ENV=docker
AWS LambdaServerless, per-request isolationimplement LambdaRuntime
Modal / E2BCloud sandboxes with language imagesimplement ModalRuntime / E2BRuntime
Firecracker / microVMsMaximum isolation, low latencyimplement FirecrackerRuntime
Only main.go changes when you swap runtimes — code_tool.go and the agent config stay the same.

Docker sandbox isolation

The example Docker runner passes safety flags to docker run:
--rm              remove container after exit (no state between calls)
--network none    block all outbound network access from LLM-generated code
--memory 128m     cap memory to prevent runaway scripts
Adjust these to match your security policy. In production, also add --cpus, --read-only, and a non-root user.

Timeout layers

LayerWhat it limitsConfigure
Per Run contextEntire agent callcontext.WithTimeoutalways wins
Agent runWhole turnWithTimeout
Tool executeSingle execute_code callWithToolExecutionConfig
SandboxScript execution wall timeYour runtime config / Docker --stop-timeout
a, _ := agent.NewAgent(
    agent.WithLLMClient(llmClient),
    agent.WithTools(NewCodeTool(runtime)),
    agent.WithAgentMode(agent.AgentModeAutonomous),
    agent.WithToolExecutionConfig(agent.ExecutionConfig{
        Timeout:     2 * time.Minute, // covers Docker image pull on first run
        MaxAttempts: 1,               // do not silently re-run side-effectful code
    }),
)

System prompt guidance

Tell the LLM not to make up output — it must call the tool first:
"When the user asks to compute or verify something with code, write a short
self-contained script and call execute_code. Read the output and explain the
result. Do not make up output — always run the code first."
Example: Code Execution.

Examples

Code Execution

execute_code tool with local and Docker runtimes

Execution config

Per-operation timeout overrides

Execution config

Tool execute timeout and max attempts

Deterministic Execution

Running predefined workflows from the agent

Tools

Custom tool implementation