# 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](/docs/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`. ```ts check import { 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 { 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), }); } } ``` ```python check import json import os from mistralai.client import Mistral from withruntime import Sandbox client = 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](/languages/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](/docs/javascript#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](/how-to/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](/docs/security#secrets-sandboxes-never-see)). ## 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](/docs/pricing)). A five-second test run costs less than a hundredth of a cent. New accounts get 50 free sandbox hours, no card: ```bash no-run npx withruntime sandbox run --trial -- bun --version ``` More: [TypeScript in a sandbox](/languages/typescript), [run untrusted LLM code](/use-cases/run-untrusted-llm-code), [grade student code](/use-cases/grade-student-code), [microVM vs container](/compare/microvm-vs-container). ## Sources Checked 25 September 2026. - [Mistral: function calling](https://docs.mistral.ai/capabilities/function_calling/) - [Mistral: code interpreter tool](https://docs.mistral.ai/agents/tools/built-in/code_interpreter) - [Mistral: Mistral Medium 3.5](https://docs.mistral.ai/models/mistral-medium-3-5-26-04), API names `mistral-medium-3-5` and `mistral-medium-latest` - [@mistralai/mistralai on npm](https://www.npmjs.com/package/@mistralai/mistralai) (2.7.0) and [mistralai on PyPI](https://pypi.org/project/mistralai/) (2.10.1) Facts on this page were checked on 25 September 2026.