Skip to main content

Run code in the sandbox

This page shows how code reaches the sandbox. Your agent calls the built-in run_python tool, and the platform runs the snippet in a throwaway container — a sandbox — which is destroyed afterward. The page then documents every request field, response field, and error message, so you can read what comes back and work out what went wrong.

Before you begin

  • You need a deployed agent. See Invoke an agent.
  • For the curl tab, the API address in your shell: export CAI_API=https://api.codyhill.dev. Invoking needs no token by default.
  • You need nothing else. The sandbox itself has no public endpoint and no authentication. That is on purpose: it is reachable only from inside the platform, and your agents reach it automatically.

Run code from an agent (the normal path)

Any agent that lists the run_python tool can run code (see built-in tools). When the model decides code is needed, the tool sends the snippet to the sandbox and folds the output into the agent's reply.

Invoke an agent with something to compute

platformctl invoke research-buddy "Please compute 2**32 in python."

You should see:

2**32 is 4294967296.
(session: 3f2c8a1e-9b7d-4e21-a6c0-5d8f13b2e470)
tool_call: run_python called with args={'code': 'print(2**32)'}

That number came from a real Python process in a single-use sandbox, not from the model guessing.

Hand the tool to your agent explicitly

If you write custom agent code, you can pass run_python in yourself. Each framework wraps the same sandbox call in its own kind of tool object.

A plain Python function — no parentheses, no wrapper:

from crusoe_adk.tools import run_python

tools = [run_python]

Whichever wrapper you use, the tool takes one argument: code, a string of Python source. It returns a formatted string holding three things from the sandbox. Those are stdout, whatever the code printed; stderr, whatever it wrote as errors; and the exit code, a number where 0 means success. When you go through run_python, the timeout is always 20 seconds.

Why you cannot call the sandbox yourself

You cannot call it directly, and that is deliberate. The sandbox has no public address and no way to sign in, so there is no customer-facing path to it today. If you need one, ask your administrator.

Everything below documents the request the platform sends on your behalf, and the answer that comes back. Read it anyway: those fields, limits, and error messages are exactly what show up in your agent's replies and logs. A successful run looks like this:

{"sandbox_id":"sandbox-x7k2p","stdout":"4294967296\n","stderr":"","exit_code":0,"duration_ms":38}

POST /v1/execute — run a Python snippet

This route runs one snippet in a warm sandbox, then destroys it. Every response carries an X-Request-Id header, which identifies that one request if you need to ask about it. Errors come back as JSON: {"error": "<message>"}.

Request fields

FieldTypeRequiredDefaultNotes
codestringyesPython source to run.
languagestringno"python"Only Python is supported. Anything else returns 400 with unsupported language "<x>".
timeout_sintegerno20How many seconds of real time the code may take. Maximum 60. 0 or absent means "use the default". Out of range returns 400 with timeout_s must be between 1 and 60.
filesarraynoFiles to write into the working directory before the code runs. Each entry is {"path": "...", "content_b64": "..."}. The content is base64-encoded, which is a way of writing any bytes — including binary ones — as plain text that fits in JSON.

Response fields (200)

FieldTypeNotes
sandbox_idstringThe single-use sandbox that ran your code, for example sandbox-x7k2p. It is different on every call.
stdoutstringEverything the code printed.
stderrstringErrors and warnings. On timeout it reads timed out after <N>s.
exit_codeinteger0 on success. -1 when the run was killed at the timeout.
duration_msintegerHow long the code ran, in milliseconds.

Input files

The platform writes every entry in the files array into the working directory before your code starts. So a snippet can read data/input.csv with a plain open().

Paths must stay inside the working directory. Say a path tries to climb out of it, like ../etc/passwd. The sandbox refuses it with file path escapes working directory: '<path>', which reaches you as a 502.

The run_python tool never sends files. It takes only code.

Timeouts kill, cleanly

When a snippet runs past its deadline, the platform kills it and every process it started. Here is a while True: pass submitted with timeout_s of 5:

{"sandbox_id":"sandbox-9d4qf","stdout":"","stderr":"timed out after 5s","exit_code":-1,"duration_ms":5003}

An infinite loop cannot hold a sandbox hostage. Through run_python, the deadline is always 20 seconds.

Note the exit_code of -1: that value means the timeout killed the run, rather than the code finishing on its own.

Error responses

StatusError messageMeaning
400invalid JSON bodyThe request body did not parse.
400unsupported language "<x>"Only "python" is accepted.
400timeout_s must be between 1 and 60Timeout out of range.
405method not allowedOnly POST works on /v1/execute.
502sandbox execution failed: <err>The sandbox could not run the code.
502the sandbox returned HTTP <code>: <detail>The runner inside the sandbox rejected the request (includes file-path escapes).
502the sandbox returned a response that could not be readThe sandbox answered with something unparseable.
503no sandbox is available right now - try again shortlyThe pool was empty for 30 seconds (the maximum wait). Retry.

The warm pool

The platform keeps a few sandboxes started and idle, so your code never waits for one to boot. A pool status endpoint, GET /v1/pool, reports four numbers. It is reachable only from inside the platform, so you cannot call it. The numbers are still a useful picture of what is happening:

{"warm": 3, "target": 3, "in_flight": 0, "created_total": 17}
FieldMeaning
warmSandboxes ready right now.
targetThe pool size the platform maintains (default 3).
in_flightExecutions running at this moment.
created_totalSandboxes created since the service started — a lifetime counter.

Every execution destroys its sandbox, and the platform creates a replacement in the background. So created_total goes up by one for every snippet that runs.

POST /v1/call — sandboxed tool calls

This is the second mode. It runs one of your own tool functions in a one-use sandbox built from the agent's own image. That sandbox carries none of the agent's credentials. Agents use this automatically when tool sandboxing is on, so you never call it yourself. Request bodies are capped at 1 MiB.

{
"image": "registry.us-east1-a.ccr.crusoecloudcompute.com/cai-ab12cd-my-agent:abc123",
"module": "agent",
"function": "get_weather",
"args": {"city": "Reykjavik"},
"timeout_s": 30
}
FieldTypeRequiredDefaultNotes
imagestringyesThe agent's container image. Missing returns 400 with image and function are required.
functionstringyesThe tool function to call.
modulestringno"agent"The Python module that defines the function.
argsobjectnoKeyword arguments for the function.
timeout_sintegerno30Maximum 120. Out of range returns 400 with timeout_s must be between 1 and 120.

Success (200):

{"sandbox_id": "tool-xyz99", "result": {"temp_c": 4}, "duration_ms": 8123}

The response leaves empty fields out rather than sending them as null. So a successful call carries no error key at all. When your tool raises an exception, an error key appears and holds the exception text.

Tool-call errors:

StatusError messageMeaning
503could not start a sandbox for this tool call: <err>The sandbox could not be created.
503the tool sandbox did not start: the tool sandbox exited before it was ready (phase Failed); the agent image must contain crusoe_adk.toolrunnerThe image lacks the tool runner.
503timed out waiting for the tool sandbox to become readyThe sandbox did not become ready within 110 seconds.
502tool execution failed: <err>The call itself failed.
502invalid response from the tool sandboxThe runner's reply was unusable (replies are capped at 8 MiB).

Unlike /v1/execute, tool calls have no warm pool. Every call waits for the platform to place a sandbox and download the agent's image. So expect several seconds rather than one.

Next steps