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.
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:
| Setting | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Add run_python and its system prompt section |
sandbox | str or null | null | Source name of the sandbox to run in. null uses the first enabled sandbox |
expose_tools | bool | true | Make the agent's other tools callable from Python. false leaves a plain Python session |
max_output_chars | int | 20000 | Truncate one call's output beyond this many characters, ending with ... [N chars truncated] |
The run_python Toolโ
| Tool | Description |
|---|---|
run_python | Run 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_callandcheck_resultdecide each call: a call a rule declines, asks about or whose result it blocks raisesPermissionError, which the code can catch, and a result a rule redacted comes back in the tool's shape. run_pythonitself 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:
| Setting | Type | Default | Description |
|---|---|---|---|
sandbox_only_sources | list[str] or null | null | Tools sources whose tools are callable only from Python |
sandbox_only_tools | list[str] or null | null | Tool names callable only from Python |
direct_only_sources | list[str] or null | null | Tools sources whose tools the model calls only directly, never from Python |
direct_only_tools | list[str] or null | null | Tool 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:
| Setting | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Run run_python in this sandbox |
workspace_directory | str | ".workspace" | Host directory mounted read-write at /workspace; created if missing |
read_only_mounts | dict[str, str] | {} | Extra mounts as {virtual_path: host_directory}, read-only. A host directory that does not exist is skipped |
max_duration_seconds | float | 60.0 | CPU 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_bytes | int | 256000000 | Memory 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 can | The code cannot |
|---|---|
Read and write /workspace | Open a network connection |
Read the read_only_mounts | Read environment variables |
| Call the tools exposed to it | Read or write any other host path |
| Use CPU and memory up to the limits | Start 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.