Skip to content
Runtime

Gemini function calling run Gemini's code in a sandbox

Declare a function tool, run each function_call step's code in an isolated microVM, and return a function_result with the output.

A Runtime sandbox lifts the two limits of Gemini's built-in code execution: the 30-second cap and the fixed library set. A command can run for up to 24 hours. A custom image carries any package you install into it. Each call still gets a fresh Firecracker microVM with the internet off. The code uses gemini-3.8-flash, which Google's model list described as its most intelligent Flash model on 25 October 2026.

Build the image once

Gemini's code execution page says "You can't install your own libraries." With your own tool, you choose the packages. Build an image with the packages that Gemini's code should find. Every sandbox then starts with them ready:

TypeScriptimport { Runtime } from "withruntime";const runtime = new Runtime();await runtime.images.build({  name: "gemini-analysis",  recipe: { pip: ["polars", "duckdb", "scipy"] },});

Building an image is free. A stored image is billed by its size (custom images).

The tool loop

Google's Interactions API returns steps. A step of type function_call carries an id, a name and arguments, which are already parsed into an object. Your reply is a function_result step with the same call_id. Send it with previous_interaction_id so Gemini keeps the context.

TypeScriptimport { GoogleGenAI } from "@google/genai";import { Sandbox } from "withruntime";const ai = new GoogleGenAI({}); // GEMINI_API_KEY, read on your serverasync function runPython(code: string) {  await using sbx = await Sandbox.create({    image: "gemini-analysis",    network: { internet: false },    timeoutSeconds: 900,    onLeaseEnd: "stop",  });  await sbx.files.write("/workspace/main.py", code);  const run = await sbx.exec(["python3", "main.py"], { timeoutMs: 600_000 });  return {    run,    text: JSON.stringify({ exit_code: run.exitCode, stdout: run.stdout, stderr: run.stderr }),  };}const tools = [  {    type: "function" as const,    name: "run_python",    description:      "Run a Python 3.12 script in a sandbox with polars, duckdb, scipy, pandas and numpy. " +      "No internet. Up to 10 minutes. Returns exit_code, stdout and stderr.",    parameters: {      type: "object",      properties: { code: { type: "string", description: "The complete script" } },      required: ["code"],    },  },];let interaction = await ai.interactions.create({  model: "gemini-3.8-flash",  input: "Simulate 10 million dice rolls with numpy and report the mean and variance.",  tools,});for (let turn = 0; turn < 8; turn++) {  const calls = (interaction.steps ?? []).filter((step) => step.type === "function_call");  if (calls.length === 0) break;  const results = [];  for (const call of calls) {    const { run, text } = await runPython(String(call.arguments.code));    results.push({      type: "function_result" as const,      name: call.name,      call_id: call.id,      is_error: run.exitCode !== 0,      result: [{ type: "text" as const, text }],    });  }  interaction = await ai.interactions.create({    model: "gemini-3.8-flash",    input: results,    tools,    previous_interaction_id: interaction.id,  });}console.log(interaction.output_text);
Pythonimport jsonfrom google import genaifrom withruntime import Sandboxclient = genai.Client()  # GEMINI_API_KEY, read on your serverdef run_python(code: str) -> tuple[bool, str]:    with Sandbox.create(        image="gemini-analysis",        network={"internet": False},        timeout_seconds=900,        on_lease_end="stop",    ) as sbx:        sbx.files.write("/workspace/main.py", code)        run = sbx.exec(["python3", "main.py"], timeout_ms=600_000)        text = json.dumps({"exit_code": run.exit_code, "stdout": run.stdout, "stderr": run.stderr})        return run.exit_code != 0, texttools = [    {        "type": "function",        "name": "run_python",        "description": "Run a Python 3.12 script in a sandbox with polars, duckdb, scipy, pandas and numpy. "        "No internet. Up to 10 minutes. Returns exit_code, stdout and stderr.",        "parameters": {            "type": "object",            "properties": {"code": {"type": "string", "description": "The complete script"}},            "required": ["code"],        },    }]interaction = client.interactions.create(    model="gemini-3.8-flash",    input="Simulate 10 million dice rolls with numpy and report the mean and variance.",    tools=tools,)for _ in range(8):    calls = [step for step in (interaction.steps or []) if step.type == "function_call"]    if not calls:        break    results = []    for call in calls:        failed, text = run_python(call.arguments["code"])        results.append(            {                "type": "function_result",                "name": call.name,                "call_id": call.id,                "is_error": failed,                "result": [{"type": "text", "text": text}],            }        )    interaction = client.interactions.create(        model="gemini-3.8-flash", input=results, tools=tools, previous_interaction_id=interaction.id    )print(interaction.output_text)

Each call gets its own sandbox, which stops when the handler returns. A recipe builds on Runtime's default image, so NumPy, pandas and matplotlib are there too (custom images). A script that loops forever ends at timeoutMs with timedOut set. It does not hold your server.

Built-in code execution or your own tool?

Gemini's {"type": "code_execution"} tool runs Python on Google's side. Its documentation, checked 25 October 2026, says "there's no additional charge for enabling code execution" beyond tokens. It also sets these limits:

Question Gemini code execution run_python on Runtime
Languages that run "Gemini is only able to execute code in Python" Python, Node.js, Bun, bash, gcc; the interpreter adds R, Java, Go
Longest run "The maximum runtime ... is 30 seconds" timeoutMs up to 24 hours per command
Libraries 37 pre-installed; "You can't install your own" Anything in your image, or pip install behind an allow list
Files CSV and text in; output files come back inline Any file, any size the disk holds, read back with files.read
Retries on error Up to 5 attempts, inside one request As many turns as your loop allows
Price Tokens only Measured CPU and memory while the sandbox runs

For quick arithmetic and small pandas jobs, the built-in tool is the shortest path. For a job that needs a package, more than 30 seconds, or a language besides Python, give Gemini your own tool.

Keys stay where they are

The Gemini key never enters the sandbox. Your server calls Google, and the sandbox receives only the script. If code inside the sandbox must call Gemini itself, store the key as a Runtime secret bound to generativelanguage.googleapis.com. The sandbox then holds a placeholder. Only the host's proxy can turn that placeholder into the key, and only on that host (secrets).

Google ADK

An agent built with Google's Agent Development Kit can use Runtime's command and file tools unchanged. In Python, they come from sandbox_tools(sbx) (Google ADK).

What it costs

Runtime bills the CPU a script uses at $0.025 per vCPU-hour, with a floor of a twentieth of a vCPU. Memory is billed at $0.0075 per GiB-hour. A 2 vCPU, 4 GiB sandbox busy on both CPUs costs $0.08 an hour, so a 30-second run costs well under a tenth of a cent (pricing). A new account gets 100 free hours of a 1 GB machine in its first 30 days, with no card needed:

Terminalnpx withruntime sandboxes run -- python3 -c 'import numpy; print(numpy.__version__)'

More: a data analysis agent, run untrusted LLM code, what a code interpreter is, Python in a 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