Skip to content
Runtime

Groq tool use run model-generated code in a sandbox, not with eval

Replace eval in Groq's tool-calling example with a sandbox: each tool call runs in its own microVM, in parallel, with no internet.

Groq returns tokens quickly. Groq's production model page listed openai/gpt-oss-120b at 500 tokens a second on 25 October 2026. The model's code never touches your server.

The problem with the sample

Groq's local tool-calling guide, read 25 October 2026, teaches the loop with a calculator. Its handler is eval(expression) in Python and eval(expression) in JavaScript, and it runs on your own machine. That is fine for showing the message shapes. In production, it runs whatever text the model returns, with your process's files, network and keys. The fix keeps Groq's loop as it is and changes only the handler.

The loop, with calls run side by side

Groq's API follows the OpenAI Chat Completions shape. The assistant message carries tool_calls. Each call then gets one role: "tool" message with its tool_call_id. A turn can carry several calls, so the handler starts one sandbox per call and waits for all of them.

TypeScriptimport Groq from "groq-sdk";import { Sandbox } from "withruntime";const groq = new Groq(); // GROQ_API_KEY, from your server's environmentasync function runPython(code: string): Promise<string> {  await using sbx = await Sandbox.create({    vcpu: 1,    memoryMiB: 1024,    network: { internet: false },    timeoutSeconds: 120,    onLeaseEnd: "stop",  });  await sbx.files.write("/workspace/main.py", code);  const run = await sbx.exec(["python3", "main.py"], { timeoutMs: 20_000 });  return JSON.stringify({    exit_code: run.exitCode,    timed_out: run.timedOut,    stdout: run.stdout,    stderr: run.stderr,  });}const tools: Groq.Chat.ChatCompletionTool[] = [  {    type: "function",    function: {      name: "run_python",      description:        "Execute a Python 3.12 script in a sandbox with no network and return its exit code, " +        "stdout and stderr. Use print() for every value you need.",      parameters: {        type: "object",        properties: { code: { type: "string", description: "A complete Python script" } },        required: ["code"],      },    },  },];const messages: Groq.Chat.ChatCompletionMessageParam[] = [  { role: "user", content: "Compute 2**521 - 1 and, separately, check whether it is prime." },];for (let turn = 0; turn < 6; turn++) {  const completion = await groq.chat.completions.create({    model: "openai/gpt-oss-120b",    messages,    tools,    tool_choice: "auto",  });  const message = completion.choices[0]!.message;  messages.push(message);  if (!message.tool_calls?.length) {    console.log(message.content);    break;  }  const outputs = await Promise.all(    message.tool_calls.map((call) => runPython(JSON.parse(call.function.arguments).code)),  );  message.tool_calls.forEach((call, i) =>    messages.push({ role: "tool", tool_call_id: call.id, content: outputs[i]! }),  );}
Pythonimport jsonfrom concurrent.futures import ThreadPoolExecutorfrom groq import Groqfrom withruntime import Sandboxclient = Groq()  # GROQ_API_KEY, from your server's environmentdef run_python(code: str) -> str:    with Sandbox.create(        vcpu=1, memory_mib=1024, network={"internet": False}, timeout_seconds=120, on_lease_end="stop"    ) as sbx:        sbx.files.write("/workspace/main.py", code)        run = sbx.exec(["python3", "main.py"], timeout_ms=20_000)        return json.dumps({"exit_code": run.exit_code, "timed_out": run.timed_out, "stdout": run.stdout, "stderr": run.stderr})tools = [    {        "type": "function",        "function": {            "name": "run_python",            "description": "Execute a Python 3.12 script in a sandbox with no network and return its exit code, "            "stdout and stderr. Use print() for every value you need.",            "parameters": {                "type": "object",                "properties": {"code": {"type": "string", "description": "A complete Python script"}},                "required": ["code"],            },        },    }]messages = [{"role": "user", "content": "Compute 2**521 - 1 and, separately, check whether it is prime."}]with ThreadPoolExecutor(max_workers=8) as pool:    for _ in range(6):        response = client.chat.completions.create(            model="openai/gpt-oss-120b", messages=messages, tools=tools, tool_choice="auto"        )        message = response.choices[0].message        messages.append(message)        if not message.tool_calls:            print(message.content)            break        codes = [json.loads(call.function.arguments)["code"] for call in message.tool_calls]        for call, output in zip(message.tool_calls, pool.map(run_python, codes)):            messages.append({"role": "tool", "tool_call_id": call.id, "content": output})

Each sandbox has 1 vCPU and 1 GiB of memory. That suits short scripts. Each command has a 20-second limit. Parallel calls never share a machine, so one call's files or crash cannot affect another. A paid account runs 100 sandboxes at the same time. An account without credit runs four.

Groq's built-in code execution

Groq also runs Python for you. Its code execution page, checked 25 October 2026, says:

Fact from Groq's page What it means for you
Add {"type": "code_interpreter"} to tools No handler to write
Supported on openai/gpt-oss-20b and openai/gpt-oss-120b Llama and other Groq models need your own tool
"Only Python is currently supported" No Node.js, bash or compiled languages
"Powered by Foundry Labs (E2B), a secure cloud environment" Groq's code environment is E2B's product
"No access to external networks"; "each request runs in a fresh, isolated environment" No pip install, no state between requests
Not a HIPAA covered service; not on regional or sovereign endpoints Check it before regulated or regional workloads

Use the built-in tool for quick calculations with GPT-OSS. Use your own tool when you use another Groq model, need a package or a language beyond Python, want files to persist between requests, or want to set the machine's size and time limit yourself. For how E2B itself compares, see E2B alternatives.

Keep the Groq key out of the sandbox

The sandbox receives only the model's script. The Groq call runs in your own process. The key needs to be a Runtime secret only when a program inside the sandbox calls Groq, such as an agent that runs there. Bound to api.groq.com, the key reaches the sandbox as a placeholder. The host's proxy replaces it on that host only (secrets).

What a call costs

A 1 vCPU, 1 GiB sandbox is billed on measured CPU at $0.025 per vCPU-hour, with a floor of a twentieth of a vCPU, and memory at $0.0075 per GiB-hour (pricing). A 10-second call that keeps its CPU busy costs 10 / 3,600 × ($0.025 + $0.0075) = $0.00009. A new account gets 100 free hours of a 1 GB machine in its first 30 days, without a card:

Terminalnpx withruntime sandboxes run -- python3 -c 'print(2**521 - 1)'

More: run untrusted LLM code, cold start, Python in a sandbox, agent sandbox.

Sources

Checked 25 October 2026.

Facts on this page were checked on 25 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card