Skip to content

rlm

rlm

RLM (Recursive Language Model) Agent — recursive decomposition via persistent REPL.

Based on the RLM paper (arxiv:2512.24601). Instead of passing long context directly in the LLM prompt, RLM stores context as a Python variable in a persistent REPL. A "Root LM" writes Python code to inspect/decompose context and makes recursive sub-LM calls via llm_query()/llm_batch().

Classes

RLMAgent

RLMAgent(engine: InferenceEngine, model: str, *, tools: Optional[List[BaseTool]] = None, bus: Optional[EventBus] = None, max_turns: Optional[int] = None, temperature: Optional[float] = None, max_tokens: Optional[int] = None, sub_model: Optional[str] = None, sub_temperature: float = 0.3, sub_max_tokens: int = 1024, max_output_chars: int = 10000, system_prompt: Optional[str] = None, interactive: bool = False, confirm_callback=None)

Bases: ToolUsingAgent

Recursive Language Model agent using a persistent REPL.

The agent generates Python code that runs in a sandboxed REPL with access to llm_query() / llm_batch() for recursive sub-LM calls. Context is stored as a REPL variable rather than injected directly into the prompt, enabling processing of arbitrarily long inputs through recursive decomposition.

Source code in src/openjarvis/agents/rlm.py
def __init__(
    self,
    engine: InferenceEngine,
    model: str,
    *,
    tools: Optional[List[BaseTool]] = None,
    bus: Optional[EventBus] = None,
    max_turns: Optional[int] = None,
    temperature: Optional[float] = None,
    max_tokens: Optional[int] = None,
    sub_model: Optional[str] = None,
    sub_temperature: float = 0.3,
    sub_max_tokens: int = 1024,
    max_output_chars: int = 10000,
    system_prompt: Optional[str] = None,
    interactive: bool = False,
    confirm_callback=None,
) -> None:
    super().__init__(
        engine,
        model,
        tools=tools,
        bus=bus,
        max_turns=max_turns,
        temperature=temperature,
        max_tokens=max_tokens,
        interactive=interactive,
        confirm_callback=confirm_callback,
    )
    # Override executor: RLM only creates one if tools are provided
    if not self._tools:
        self._executor = None  # type: ignore[assignment]
    self._sub_model = sub_model or model
    self._sub_temperature = sub_temperature
    self._sub_max_tokens = sub_max_tokens
    self._max_output_chars = max_output_chars
    self._custom_system_prompt = system_prompt

Functions