This release brings dspy-monty-interpreter up to the DSPy 3.3.1 CodeInterpreter protocol and Monty 0.0.20.
Upgrading from 0.3.0
DSPy 3.3 removed the interpreter= argument from dspy.RLM. There are now two ways to give RLM an interpreter.
Create a factory to instantiate a new interpreter on each call. DSPy calls a factory it once per forward() and shuts the interpreter down afterwards. MontyInterpreter.factory(...) takes the same arguments as the constructor:
rlm = dspy.RLM(
"context -> answer",
interpreter_factory=MontyInterpreter.factory(request_timeout=10.0),
)Alternatively, reuse an interpreter instance across calls by passing it as the first positional argument when you call the module. RLM injects its tools into it but never shuts it down, which is the same contract as the old interpreter=:
interpreter = MontyInterpreter(request_timeout=10.0)
result = rlm(interpreter, context="What is 2 + 2?")However, keep interpreter_factory=MontyInterpreter on the RLM even when you pass an interpreter positionally. RLM builds its prompt once, at construction time, from the factory's execution_instructions. And about those…
Execution instructions for the model
The interpreter now provides execution_instructions, which dspy.RLM adds to its core prompt. The text tells the model which stdlib modules Monty has, the syntax it doesn't support, and that it cannot pass bound methods to tools. In our testing this removed Monty-specific errors from multi-step analysis tasks.
When you pass file system mounts, the instructions describe each mounted directory. It reads like so:
Mounted directories (explore with os.listdir(path), pathlib.Path(path).iterdir(), and open(path); os.path and os.walk are not available):
- /data (read-only) containing q3/, readme.md
- /scratch (overlay: writable, but writes are discarded when each execution ends) containing (empty)
The listing is bounded so a large mount cannot bloat the prompt. Up to mount_listing_limit entries (default 20) are listed by name. Past that the model gets a count and a summary by extension instead. Pass mount_listing_limit=0 to list only the path and mode. Without mounts the section says the filesystem is unavailable, so the model does not go looking for one.
Error handling that matches DSPy 3.3
Runtime errors in sandbox code, and in tools it calls, now raise CodeExecutionError, a subclass of CodeInterpreterError. RLM feeds these back to the model as a correction turn instead of ending the run. Only a crashed or timed-out worker still raises a bare CodeInterpreterError, which ends the run.
SUBMIT() now stops execution immediately. Code after it no longer runs.
ResourceLimits(max_memory=...) is now enforced by Monty's allocator. A violation raises CodeExecutionError and the session keeps its state.
Lifecycle callbacks
DSPy's interpreter callbacks now fire: on_interpreter_startup_*, on_interpreter_execute_*, on_interpreter_tool_call_*, and on_interpreter_shutdown_*. Register a BaseCallback globally with dspy.configure(callbacks=[...]) or per instance with the new MontyInterpreter(callbacks=[...]) argument. Tool calls nest under the execute() call that made them, and they no longer fire on_tool_* twice under RLM.
Other changes
start()now checks out a REPL session right away instead of doing nothing.- Sandbox code can use
collections,itertools,dataclasses, and decorators, which are new in Monty 0.0.20.
Bug fixes
execution_instructionsnow separates the filesystem section from the base text with a newline. In 0.4.0 the mount description ran straight on from the previous sentence.