Skip to content

Repository files navigation

Rho

R-CMD-check Lifecycle: experimental

An asynchronous agent runtime for R, inspired by Pi.

Rho expresses Pi’s provider and agent architecture through S7 classes and open generics. nanonext provides asynchronous I/O, and mirai provides worker evaluation.

An effectful operation returns a task or stream. Waiting is an explicit edge operation, so a CLI can block while a Shiny application, extension, or another agent keeps composing work.

An agent run

The deterministic provider is the executable specification for the same event protocol used by live providers. rho_prompt() returns before the result is collected; rho_await() is the explicit wait.

library(rho)

agent <- rho_agent(
  provider = rho_faux_provider(),
  model = rho_model(provider = "faux", id = "faux")
)

run_task <- rho_prompt(agent, "hello from R")
rho_is_task(run_task)
#> [1] TRUE

run <- rho_await(run_task, timeout = 5000)
c(
  status = run@status,
  answer = run@messages[[2L]]@content[[1L]]@text
)
#>               status               answer
#>          "completed" "faux: hello from R"

The transcript contains typed messages and content; the lifecycle is an ordered sequence of typed events rather than callbacks hidden inside the provider.

vapply(run@events, function(event) event@type, character(1))
#>  [1] "agent_start"    "turn_start"     "message_start"  "message_end"
#>  [5] "message_start"  "message_update" "message_update" "message_update"
#>  [9] "message_end"    "turn_end"       "agent_end"      "agent_settled"

OpenAI Codex with explicit credentials

Live authentication is a value passed to the provider catalog. Rho does not search environment variables or process-global credential state. The importer accepts a Pi or Codex auth file only when its path is supplied by the caller.

credential_path <- getOption("rho.openai_codex_credential")
credential <- rho_load_openai_codex_credential(
  path = credential_path
) |>
  rho_await(timeout = 5000)

codex_provider <- rho_openai_codex_provider()
models <- rho_models(
  providers = list(codex_provider),
  credentials = rho_memory_credential_store(
    list(`openai-codex` = credential)
  )
)

codex_model <- rho_openai_codex_model("gpt-5.3-codex-spark")
codex_agent <- rho_agent(
  provider = models,
  model = codex_model,
  tools = list(rho_tool_r()),
  stream_options = list(reasoning_effort = "minimal")
)

codex_run <- rho_prompt(
  codex_agent,
  paste(
    "Call the r tool exactly once with code sum((1:100)^2).",
    "Then answer with only the integer result."
  )
) |>
  rho_await(timeout = 120000)

tool_result <- codex_run@tool_results[[1L]]
result <- tool_result@content[[1L]]@text

codex_example <- data.frame(
  model = codex_model@id,
  status = codex_run@status,
  tool = tool_result@tool_name,
  result = result
)
codex_example

Rebuild this example by supplying the credential file explicitly:

Rscript scripts/render-readmes.R /absolute/path/to/auth.json

Package layout

rho is one installable R package. Its task, HTTP, provider, agent, extension, compute, graphics, coding, and bioinformatics contracts remain distinct components within one namespace. DuckDB, mirai, and httr2/curl backends use optional dependencies. Bounded test assertions are internal utilities.

The components have separate responsibilities, not separate package boundaries. The current rho.ext runtime is not connected to rho.agent; rho.bio.agent only lists registered manifests; the DuckDB SQL guard is lexical; and coding file/Bash tools still inherit host filesystem and environment authority. These gaps are tracked in issues #7, #9, and #11.

Provider implementations live in rho. OpenAI Codex, GitHub Copilot, Z.ai, OpenAI, Anthropic, Ollama, and the deterministic faux provider therefore share one typed provider surface without a package per API. The Pi parity ledger distinguishes complete wire adapters from request translators whose normalized stream is not yet complete. OpenAI, OpenAI Codex, GitHub Copilot, Z.ai, and Anthropic have executable normalized-stream fixtures; the ledger records the executable and external-account evidence for each adapter.

Bioinformatics contracts and adapters consume the provider and agent substrate without defining it.

Install and develop

Rho targets R 4.6 or newer. Install the development package from a checkout. The required nanonext development build comes from the pinned RGenomicsETL fork, not the r-lib release; the Remotes field declares this source.

git clone git@github.com:RGenomicsETL/Rho.git
cd Rho
Rscript -e 'remotes::install_deps(dependencies = TRUE)'
make install

The authored API documentation is roxygen; the authored tests are R Markdown files under inst/tinytest/rmd/. Generated manuals, the namespace, executable tests, and the README are reproducible from their sources.

make format       # Air
make rd           # roxygen2
make purl-tests   # Rmd tests -> executable tinytest files
make rdm          # rebuild README.md
make test         # run unified tinytest suite
make check        # R CMD build and R CMD check --no-manual

The Pi parity ledger records behavioral contracts and the fixtures that verify them. Public release and addition to the RGenomicsETL R-universe follow green package checks, live provider checks, documentation, and secret scanning. The exact sequence is recorded in the publishing guide.

License

MIT.

About

An asynchronous agent runtime for R

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages