Skip to contents

A subprocess execution backend for running R code generated by LLMs. Uses callr for process isolation, timeout protection, output capture, and structured result handling.

Details

RCodeRunner provides:

  • Process isolation: Code runs in a separate R process via callr

  • Timeout protection: Configurable timeout prevents runaway execution

  • Output capture: Captures stdout, stderr, messages, and warnings

  • Context passing: Inject data into the execution environment

  • Output limiting: Truncates large outputs to prevent memory issues

Security note: r_code_runner() is a trusted-input-only backend. callr starts a separate process, but that process retains the host user's file, network, environment, and operating-system permissions. Pattern checks are only defense in depth and can be bypassed. For untrusted inputs, provide a runner backed by a container or OS-level sandbox.

Code-executing modules accept any runner that implements the dsprrr runner protocol. A runner must expose execute(code, context = list()) and policy() methods. policy() returns a uniquely named list containing at least backend (character), trust (character), and sandboxed (logical). execute() returns one uniquely named list. success and result are required. Missing stdout, stderr, messages, and warnings fields are normalized to empty strings, and missing duration_ms is normalized to NA. A failed result must include a non-empty error. Its error_type is either "execution" for code the model may repair or "interpreter" for a terminal process/protocol failure. Legacy runners that omit error_type are treated as reporting a repairable execution failure. A successful result may omit error and error_type.

Code-executing modules accept exactly one runtime source. Passing runner retains that caller-owned object and never closes it. Passing a zero-argument interpreter_factory creates one fresh invocation-owned runner. Factory results may implement idempotent start() and must implement idempotent terminal shutdown() or its compatibility alias close(). dsprrr starts a factory runner before use and shuts it down exactly once on success, error, or interrupt.

Examples

if (FALSE) { # \dontrun{
runner <- r_code_runner(timeout = 5)

# Simple execution
result <- runner$execute("1 + 1")
result$result
# [1] 2

# With context
result <- runner$execute(
  "mean(.context$data$mpg)",
  context = list(data = mtcars)
)
result$result
# [1] 20.09062

# Timeout handling
result <- runner$execute("Sys.sleep(100)")
result$success
# [1] FALSE
result$error
# "Execution timed out after 5 seconds"
} # }