Files
openhuman/src/openhuman/rlm/README.md
T

3.9 KiB
Raw Blame History

rlm — language-based workflows (Rhai .ragsh REPL)

Exposes TinyAgents' Rhai-backed .ragsh session runtime (the repl cargo feature, tinyagents::ReplSession) as a first-class rlm tool so the orchestrator model can author and execute its own workflow scripts — fan-out over subagents, batched tool/model calls, loops, dedup/verify pipelines — and run them deterministically, in the spirit of Claude Code Workflows and Recursive Language Models.

One orchestrator tool call maps to one eval_cell: the model writes a Rhai cell, the cell runs against a persistent per-session namespace (top-level let bindings survive into the next cell), and the structured result flows back as the tool result. The orchestrator's own turn loop is the CodeAct driver loop.

Module shape

File Role
mod.rs Exports only (no controller schemas in v1).
types.rs RlmSessionId, RlmEvalRequest/RlmEvalResponse, RlmLimitsOverride, RlmCallSummary, serde types.
policy.rs Maps openhuman autonomy tier + tool_timeout clamps → tinyagents::ReplPolicy (fail-closed, bounded).
bridge.rs Builds the CapabilityRegistry<()>: openhuman tools (approval-gated, scope-filtered) + provider models + subagents.
sessions.rs RlmSessionManager: LRU + idle-TTL bounded map of persistent ReplSessions, keyed <thread>:<session_id>, one cell at a time.
ops.rs eval_rlm_cell: spawn_blocking + outer timeout, cancellation wiring, event forwarding, error → model-consumable result.
tools.rs RlmTool (the rlm tool: schema, permission, scope, timeout, display).

Fail-closed guarantees

Every failure mode returns a model-consumable tool result — never a panic, never a hung turn:

  • Layered time bounds: (1) rhai on_progress deadline for pure script loops; (2) bridge_block_on timer race for hung capability futures; (3) an outer tokio::time::timeout(policy.timeout + 5s) around spawn_blocking; (4) the harness ToolTimeout::Secs backstop above all of them. The tool's own timeout is always set below the harness backstop.
  • Bounded sessions: LRU cap (16) + idle TTL (30 min); a second concurrent call on a busy session returns a typed "session busy" error rather than deadlocking; a poisoned/errored session is dropped, never reused.
  • Bounded work per session: ReplPolicy caps on operations, output bytes, script bytes, and per-kind call counts. full tier may raise call-count limits up to a hard 2× ceiling via the tool's limits arg; readonly tier does not get the tool at all.
  • Cancellation end-to-end: the turn's run-cancellation token drives a ReplCancelFlag watcher, so a user cancel drops an in-flight cell (script or capability call) promptly; the session is left resumable.

Approval & security (bridged tools keep their own gates)

The RLM bridge restricts callable tools to the parent turn's visible_tool_names, and excludes recursion/duplication hazards: rlm itself, spawn_subagent/spawn_parallel_agents (use agent_query instead), and run_workflow/await_workflow. ToolScope::CliRpcOnly tools are denied.

Approval gating is not on the tinyagents repl bridge path (it lives in the harness wrap_tool middleware, which the REPL bypasses), so the bridge itself invokes ApprovalGate::intercept_audited (+ record_execution) for any tool whose external_effect_with_args is true, failing closed on denial.

Capability surface exposed to scripts

model_query, tool_call, agent_query, their *_batched variants, emit, and answer. Graph authoring/execution (graph_*) is out of scope for v1 (the REPL's graph_run returns a reference, not an execution).

Kill switch & rollout

The tool is not registered when the autonomy tier is readonly or when OPENHUMAN_RLM=0; default-on for supervised/full. Reverting the registration line disables the surface without touching the domain.