Skip to main content

How to Configure the Python REPL

๐Ÿ”ง Tools ยท ๐Ÿ“‹ Prompt

The REPL provider adds one tool, run_python: a sandboxed Python session in which the agent's other tools are async functions with the same names and parameters. The agent can loop over search results, join and filter data, and keep large tool results in variables instead of reading them, printing only what it needs.

Optional extra

Install with pip install "zetaalpha.agents[repl]". It installs pydantic-monty, the interpreter behind the monty sandbox. Without it, run_python answers Error: the Python tool needs the pydantic-monty package.

Enable the REPLโ€‹

The provider and one sandbox must both be on:

{
"agent_configuration": {
"repl_provider_configuration": { "enabled": true },
"monty_repl_sandbox_configuration": { "enabled": true, "workspace_directory": ".workspace" }
}
}
za agents capabilities repl-sandboxes list
za agents capabilities repl-sandboxes configure monty
za agents capabilities repl-sandboxes settings

za agents add and za agents configure also ask whether to enable the Python REPL, and switch on monty when you say yes.

Provider Settingsโ€‹

repl_provider_configuration:

SettingTypeDefaultDescription
enabledboolfalseAdd run_python and its system prompt section
sandboxstr or nullnullSource name of the sandbox to run in. null uses the first enabled sandbox
expose_toolsbooltrueMake the agent's other tools callable from Python. false leaves a plain Python session
max_output_charsint20000Truncate one call's output beyond this many characters, ending with ... [N chars truncated]

The run_python Toolโ€‹

ToolDescription
run_pythonRun code in the session. Returns what the code printed, then => and the repr of the last expression's value; (no output) when there is neither. A failure returns a line starting with Error: or SyntaxError: instead of failing the turn

Variables, functions and imports survive between calls within one agent run. The provider closes the session when the run ends, so the next turn starts with empty variables; files written to /workspace stay.

The system prompt gets a ## Python section: when to use the REPL, what the sandbox can reach and which Python subset it runs, and a Python stub for each tool callable from it.

Calling Tools from Pythonโ€‹

Each tool callable from Python is an async function. await it, positionally in the order of its parameters or by keyword, and the result comes back as plain Python data (dicts, lists, strings, numbers). asyncio.gather runs several calls in parallel.

import asyncio

queries = ["solid-state electrolytes", "sodium-ion anodes", "lithium-sulfur cathodes"]
pages = await asyncio.gather(*(search(q, page_size=20) for q in queries))
for query, page in zip(queries, pages):
print(query, page["total_hits"])

The system prompt lists each callable tool as a stub with its signature, summary and Returns: section. A tool's parameter descriptions are added to its stub only when the tool is sandbox-only, since the model already has them in the tool definitions otherwise.

Python gets the tools of the model call it runs in, after the tool rules decided:

  • A tool the rules hide is not callable.
  • A tool that asks the user first is left out of the stubs, and a call to it fails with an error telling the agent to call it directly, because Python cannot ask the user. It runs from Python once the user allowed it for the chat.
  • A rule's check_call and check_result decide each call: a call a rule declines, asks about or whose result it blocks raises PermissionError, which the code can catch, and a result a rule redacted comes back in the tool's shape.
  • run_python itself is not callable from Python.

Who May Call a Toolโ€‹

Every tool has allowed_callers, ["direct", "sandbox"] by default: direct is the model's own tool call, sandbox is a call from Python. The model is sent only tools that allow direct; Python gets only tools that allow sandbox.

For built-in tools sources, tools_provider_configuration sets it:

SettingTypeDefaultDescription
sandbox_only_sourceslist[str] or nullnullTools sources whose tools are callable only from Python
sandbox_only_toolslist[str] or nullnullTool names callable only from Python
direct_only_sourceslist[str] or nullnullTools sources whose tools the model calls only directly, never from Python
direct_only_toolslist[str] or nullnullTool names the model calls only directly, never from Python

A source or tool listed as both sandbox-only and direct-only is a configuration error. MCP tools and the tools of other providers keep the default and are callable both ways.

"tools_provider_configuration": {
"sandbox_only_sources": ["dataframe_tools"],
"direct_only_tools": ["commit_attempt", "read_attempt", "request_refinement"]
}

Sandbox-only keeps a chatty source out of the model's tool list while scripts still use it. Direct-only keeps a decision with the model: a script cannot commit an attempt or request a refinement.

A tool you write sets the same field on its definition:

from zav.agents_sdk import Tool

Tool(name="bulk_lookup", description="...", executable=bulk_lookup, allowed_callers=["sandbox"])

The monty Sandboxโ€‹

monty runs code in pydantic-monty, a Python interpreter written in Rust, inside the agent's process.

monty_repl_sandbox_configuration:

SettingTypeDefaultDescription
enabledboolfalseRun run_python in this sandbox
workspace_directorystr".workspace"Host directory mounted read-write at /workspace; created if missing
read_only_mountsdict[str, str]{}Extra mounts as {virtual_path: host_directory}, read-only. A host directory that does not exist is skipped
max_duration_secondsfloat60.0CPU time budget for one session, summed over its calls. When it is spent the session is recreated, its variables are lost, and the tool says so
max_memory_bytesint256000000Memory cap for the session
"monty_repl_sandbox_configuration": {
"enabled": true,
"workspace_directory": ".workspace",
"read_only_mounts": { "/docs": "docs", "/attempts": "attempts" },
"max_duration_seconds": 120
}

The interpreter runs a Python subset. Available standard library modules: asyncio (top-level await, no event loop), base64, binascii, collections, dataclasses, datetime, functools, itertools, json, math, os, pathlib, re, sys, typing, unicodedata. There are no third-party packages, no class inheritance, no @classmethod, @staticmethod or @property, no generators, no match, and no eval or exec. The system prompt tells the model this, so it does not discover it one failed import at a time.

Securityโ€‹

The sandbox is a boundary between the code the model writes and the host that runs the agent.

The code canThe code cannot
Read and write /workspaceOpen a network connection
Read the read_only_mountsRead environment variables
Call the tools exposed to itRead or write any other host path
Use CPU and memory up to the limitsStart processes or import packages outside the subset

Tools are the only way out. A tool called from Python runs in the host, with the agent's configuration and the request's credentials, and only its JSON-serializable result enters the sandbox. API keys, auth headers and tenant settings stay in the host. Tools can still reach what their source reaches: web_fetch called from Python fetches the web, so expose to Python only what the agent may do by itself. Use direct_only_* for tools that must not run from a script, and the tool rules to hide tools altogether.

Everything in /workspace is written by model-generated code. Keep it data only: never execute it, import it or load it as configuration on the host. Mount read-only only directories you are willing to show the model, never one holding credentials.

Custom Sandboxesโ€‹

A sandbox is a ReplSandbox source (zav.agents_sdk.adapters.repl). It implements run(code, host_functions), which returns the rendered output and never raises, to_prompt(), which says what the model must know about its filesystem and limits, and optionally aclose(). The provider owns the tool, the bridge to the agent's tools, the prompt and output truncation; the sandbox only runs code. Register its factory with AgentDependencyRegistry and select it with sandbox. za agents capabilities repl-sandboxes add <name> scaffolds one.