Runtime

Mistral function calling: run code from Mistral models in a sandbox

Add a run_code tool to chat.complete, run each tool call in a microVM with no internet, and append a tool message with the result.

Runtime runs the code Mistral writes, in Python, JavaScript, TypeScript or bash, from Chat Completions, the API where Mistral's own code interpreter does not work. Mistral's documentation says its code_interpreter tool "works with the Conversations API and the Agents API" and "isn't supported in the Chat Completions API". A function tool backed by a Runtime sandbox works in any of them. Each run gets a Firecracker microVM that started its first command in 351 ms at the median on 24 September 2026 (speed). The model here is mistral-medium-3-5, Mistral Medium 3.5, which Mistral lists as its frontier model for agentic and coding work, checked 25 September 2026.

The loop

Mistral's Chat Completions follow the familiar shape: the reply's tool_calls hold an id, a function name and arguments; you append the assistant message, then one tool message per call with the same id. The TypeScript SDK spells the fields in camelCase: toolCalls, toolCallId.

TypeScriptimport { Mistral } from "@mistralai/mistralai";import type { ChatCompletionRequestMessage } from "@mistralai/mistralai/models/components";import { Sandbox } from "withruntime";const client = new Mistral({ apiKey: process.env.MISTRAL_API_KEY ?? "" });const RUNNERS = {  python: { file: "main.py", argv: ["python3", "main.py"] },  javascript: { file: "main.mjs", argv: ["node", "main.mjs"] },  typescript: { file: "main.ts", argv: ["bun", "main.ts"] },  bash: { file: "main.sh", argv: ["bash", "main.sh"] },} as const;type Language = keyof typeof RUNNERS;async function runCode(language: Language, code: string): Promise<string> {  const runner = RUNNERS[language] ?? RUNNERS.python;  await using sbx = await Sandbox.create({    vcpu: 1,    memoryMiB: 2048,    network: { internet: false },    timeoutSeconds: 300,    onLeaseEnd: "stop",  });  await sbx.files.write(`/workspace/${runner.file}`, code);  const run = await sbx.exec([...runner.argv], { timeoutMs: 60_000 });  return JSON.stringify({    exit_code: run.exitCode,    timed_out: run.timedOut,    stdout: run.stdout,    stderr: run.stderr,  });}const tools = [  {    type: "function" as const,    function: {      name: "run_code",      description:        "Run a complete program in an isolated Linux sandbox with no internet and return " +        "exit_code, timed_out, stdout and stderr. Python 3.12, Node.js 24, Bun and bash.",      parameters: {        type: "object",        properties: {          language: { type: "string", enum: Object.keys(RUNNERS) },          code: { type: "string" },        },        required: ["language", "code"],      },    },  },];const messages: ChatCompletionRequestMessage[] = [  {    role: "user",    content:      "Write a TypeScript function that checks a Luhn number, test it on 4539 1488 0343 6467, and run it.",  },];for (let turn = 0; turn < 8; turn++) {  const response = await client.chat.complete({ model: "mistral-medium-3-5", messages, tools });  const message = response.choices[0]?.message;  if (!message) break;  messages.push({ ...message, role: "assistant" });  if (!message.toolCalls?.length) {    console.log(message.content);    break;  }  for (const call of message.toolCalls) {    const args =      typeof call.function.arguments === "string"        ? JSON.parse(call.function.arguments)        : call.function.arguments;    messages.push({      role: "tool",      name: call.function.name,      toolCallId: call.id ?? "",      content: await runCode(args.language, args.code),    });  }}
Pythonimport jsonimport osfrom mistralai.client import Mistralfrom withruntime import Sandboxclient = Mistral(api_key=os.environ["MISTRAL_API_KEY"])RUNNERS = {    "python": ("main.py", ["python3", "main.py"]),    "javascript": ("main.mjs", ["node", "main.mjs"]),    "typescript": ("main.ts", ["bun", "main.ts"]),    "bash": ("main.sh", ["bash", "main.sh"]),}def run_code(language: str, code: str) -> str:    file, argv = RUNNERS.get(language, RUNNERS["python"])    with Sandbox.create(        vcpu=1, memory_mib=2048, network={"internet": False}, timeout_seconds=300, on_lease_end="stop"    ) as sbx:        sbx.files.write(f"/workspace/{file}", code)        run = sbx.exec(argv, timeout_ms=60_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_code",            "description": "Run a complete program in an isolated Linux sandbox with no internet and return "            "exit_code, timed_out, stdout and stderr. Python 3.12, Node.js 24, Bun and bash.",            "parameters": {                "type": "object",                "properties": {"language": {"type": "string", "enum": list(RUNNERS)}, "code": {"type": "string"}},                "required": ["language", "code"],            },        },    }]messages = [    {"role": "user", "content": "Write a TypeScript function that checks a Luhn number, test it on 4539 1488 0343 6467, and run it."}]for _ in range(8):    message = client.chat.complete(model="mistral-medium-3-5", messages=messages, tools=tools).choices[0].message    messages.append(message)    if not message.tool_calls:        print(message.content)        break    for call in message.tool_calls:        args = call.function.arguments        args = json.loads(args) if isinstance(args, str) else args        messages.append(            {"role": "tool", "name": call.function.name, "content": run_code(args["language"], args["code"]), "tool_call_id": call.id}        )

The program's text goes into a file and runs as an argument list, so the model's code reaches python3, node, bun or bash inside the sandbox and never a shell on your server. Bun runs TypeScript directly, with no build step (Bun). Each call's sandbox has 1 vCPU and 2 GiB, and it stops when the handler returns.

Three ways to run code with Mistral

Approach API it works with Where the code runs
Mistral's code_interpreter built-in tool Agents and Conversations APIs only Mistral's "isolated container"
A function tool run on your own server Any Your machine, beside your data and keys
A function tool run in a Runtime sandbox Any, including Chat Completions A microVM with its own kernel, no route to your network

Mistral's page on the built-in tool, checked 25 September 2026, does not state its languages, packages or time limits. With your own tool, all three are settings you choose: the runners above, the image, and timeoutMs.

Keep a sandbox between calls

When the model builds on its own earlier output, create the sandbox once per conversation and run every call in it, so a file written in one call is there in the next. To keep variables in memory between calls, use the code interpreter: sbx.interpreter.run(code, { language: "typescript" }) keeps state per language, and adds R, Java and Go. A sandbox that goes quiet can pause itself with idlePauseSeconds and wake on the next call.

Keys and network

MISTRAL_API_KEY stays on your server; the sandbox gets only the program. If the program needs a package, allow the registry by name, install, and switch the internet off before running the model's code (turn off sandbox internet). If code in the sandbox must call Mistral itself, store the key as a Runtime secret bound to api.mistral.ai, which the sandbox sees only as a placeholder (secrets).

What it costs

A 1 vCPU, 2 GiB sandbox costs $0.01625 an hour while it waits (memory at $0.0075 per GiB-hour plus the CPU floor of a twentieth of a vCPU at $0.025 per vCPU-hour) and $0.04 an hour with its CPU busy (pricing). A five-second test run costs less than a hundredth of a cent. New accounts get 50 free sandbox hours, no card:

Terminalnpx withruntime sandbox run --trial -- bun --version

More: TypeScript in a sandbox, run untrusted LLM code, grade student code, microVM vs container.

Sources

Checked 25 September 2026.

Facts on this page were checked on 25 September 2026.