Documentation Index
Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt
Use this file to discover all available pages before exploring further.
PyRepl
PyRepl is a persistent IPython REPL running in a subprocess. It gives the model a continuous execution environment where variables persist across calls and runtime primitives are accessible without imports.
In 0.8.1, PyRepl remains the public facade while its internals are split into focused components: worker lifecycle (pyrepl_worker_client.py), execute/reset orchestration (pyrepl_execution.py), primitive host integration (pyrepl_primitive_host.py), tool factory/output formatting (pyrepl_tools.py), audit logging (pyrepl_audit.py), and input bridging (pyrepl_input_bridge.py / pyrepl_input_mixin.py). This is an internal architecture cleanup; user-facing usage stays the same.
Core Properties
- Persistent state — Variables defined in one
execute_code call are available in the next
- Isolated process — Runs in a separate subprocess (multiprocessing spawn). Crashes don’t kill the main process
- Runtime injection — The
runtime object is globally available. No imports needed
- Streaming output — stdout/stderr stream in real-time via custom events
- Timeout protection — Default 600s per execution. Configurable
Setup
from SimpleLLMFunc.builtin import PyRepl
repl = PyRepl(working_directory="/path/to/workspace")
# Use as toolkit in an agent
@llm_chat(llm_interface=llm, toolkit=repl.toolset, stream=True)
async def agent(message: str, history: list | None = None):
"""A code-executing agent."""
pass
execute_code
Run arbitrary Python code in the persistent REPL:
result = await execute_code(code="""
import math
x = math.sqrt(144)
print(f"Result: {x}")
x
""")
# Returns: {"stdout": "Result: 12.0\n", "return_value": "12.0", "execution_time_ms": ...}
Return value is the last expression’s repr (like IPython).
reset_repl
Clear all user variables but keep runtime backends:
await reset_repl()
# After this: `x` is gone, but `runtime.selfref.context.inspect()` still works
Runtime Namespace
Inside execute_code, the runtime object provides:
# Meta-primitives (always available)
runtime.list_primitives()
runtime.list_primitive_specs()
runtime.get_primitive_spec("selfref.context.compact")
runtime.list_backends()
# SelfRef primitives (when selfref is active)
runtime.selfref.context.inspect()
runtime.selfref.context.remember("important fact")
runtime.selfref.context.forget("exp_001")
runtime.selfref.context.compact(goal=..., instruction=..., ...)
runtime.selfref.fork.spawn(task=..., instruction=...)
runtime.selfref.fork.gather_all()
# Custom pack primitives (if installed)
runtime.metrics.increment_counter("files_read")
Streaming Output
PyRepl emits custom events for real-time output:
| Event Name | Data | When |
|---|
kernel_stdout | {"text": "..."} | Each stdout flush |
kernel_stderr | {"text": "..."} | Each stderr flush |
Consume in your event handler:
from SimpleLLMFunc.hooks import is_event_yield, CustomEvent
async for output in agent("run some code", history):
if is_event_yield(output):
if isinstance(output.event, CustomEvent):
if output.event.event_name == "kernel_stdout":
print(output.event.data["text"], end="")
Output Truncation
If a tool result exceeds ~20,000 tokens:
- Full output is written to a temporary file
- Truncated version (first ~4,096 tokens) + file path is returned to the model
- The model can use
read_file to access specific parts
Enable per-agent with _too_long_to_file=True.
Working Directory
repl = PyRepl(working_directory="/path/to/project")
The REPL starts in this directory. os.getcwd() inside execute_code returns this path.
Installing Custom Primitive Packs
from SimpleLLMFunc.runtime import PrimitivePack
my_pack = PrimitivePack(namespace="mytools", backend=..., primitives=[...])
repl.install_primitive_pack(my_pack)
After installation, runtime.mytools.* is available in execute_code.
SelfRef Integration
When using self_reference_key on the agent, the framework automatically:
- Creates a SelfReference backend
- Builds the selfref primitive pack
- Installs it in the PyRepl instance
- Makes
runtime.selfref.* available
@llm_chat(
llm_interface=llm,
toolkit=repl.toolset,
self_reference_key="agent_main",
)
async def agent(message: str, history: list | None = None):
"""Agent with code execution + self-reference."""
pass
Practical Pattern: CodeAct Agent
The “CodeAct” pattern uses PyRepl as the primary action surface — the model writes Python to accomplish tasks instead of using separate tools for each operation:
repl = PyRepl(working_directory=workspace)
file_tools = FileToolset(workspace).toolset
@llm_chat(
llm_interface=llm,
toolkit=[*repl.toolset, *file_tools],
self_reference_key="agent_main",
stream=True,
)
async def coding_agent(message: str, history: list | None = None):
"""
Solve coding tasks by writing and executing Python.
Use execute_code for inspection, computation, and verification.
Use file tools for reading and editing project files.
Use runtime.selfref.context.compact(...) when context grows large.
"""
pass
→ API Reference: Builtins