These docs describe unreleased changes on main. See the latest release.

rlmesh.Session

classfrom rlmesh import Session[source]

A model bound to one env: drive it by hand, or pump whole episodes.

Session()

The neutral pair-driver returned by rlmesh.session(). reset / predict / step drive one step at a time – predict applies the model’s adapter (resolved from the env’s published contract) around the model’s own predict, replaying an action chunk one action per step when execution_horizon > 1 and the model defines predict_chunk. run pumps whole episodes and returns a typed RunResult.

The env connection is opened lazily on first reset (manual driving); run drives whole episodes through the same primitives and leaves the session open, so a caller-held session runs as often as you like. Close it yourself – close() or the with block; after that, any further use raises. (The one-shot rlmesh.run() / Model.run create their session internally and close it when the run ends.)

selected_workflow_edition

property[source]
property selected_workflow_edition: str

The workflow edition this session runs at, in the spelling the peers agreed on.

On a served model it is the floor across the env, the model, and this runtime, settled when the session was opened; on a local model the env leg is the whole negotiation, so it is what that connection settled on. Named apart from the workflow_edition declaration surfaces: this is what was agreed, not what this side asked for.

done

property[source]
property done: bool

Whether the current episode has terminated or truncated.

reset

function[source]
reset(*, seed: int | None = None, trial_index: int | None = None)

Begin a new episode: end the previous one, then reset the env and adapter.

Ending the previous episode fires the model’s on_episode_end (the local per-episode boundary), so a stateful model clears its state between episodes on the hand-driven path too, not only via run().

trial_index is the 0-based ordinal of this episode in a benchmark’s trial sweep, delivered as reset(options={"trial_index": ...}) – but only to an env that declared the key in EnvFactory.reset_options. Passing one to an env that did not warns and resets without it.

predict

function[source]
predict(observation: ObsT)

Map one env observation to an env-ready action (the model’s adapter applied).

step

function[source]
step(action: ActT)

Apply one action to the env; record reward and termination.

With a viewer paced by View.step_hz, returns no sooner than the next step is due.

contract

property[source]
property contract: Any

The connected env’s contract (connects on first use).

num_envs

property[source]
property num_envs: int

Lanes the connected env runs (a session drives one).

frame_sources

function[source]
frame_sources()

The env’s image roles and render() source, as the viewer sees them.

reader

function[source]
reader(*items: object)

Build a read-only, role-addressed view over this env’s observations.

Each item is a role constant – kept in the env’s native encoding – or a model-input leaf declaring the encoding you want (Image(IMAGE_PRIMARY, layout="hwc"), State(EEF_POS)). The returned Reader maps a raw observation to {role: value} through the same adapter pipeline a model uses, so it is encoding-agnostic across envs and runs identically in the native core. Resolved once here, reused each step::

read = sess.reader(Image(IMAGE_PRIMARY, layout=“hwc”), EEF_POS) obs, _ = sess.reset() while not sess.done: screen.show(read(obs)[IMAGE_PRIMARY]) obs, *_ = sess.step(sess.predict(obs))

A bare role is desugared to the env-native leaf for that role (by the env’s own tag); pass an explicit leaf to override the encoding.

read

function[source]
read(observation: object, item: object)

One-shot read of a single role from one observation.

The single-value convenience for reader() – item is a role constant or a model-input leaf. The reader is resolved once and cached per item, so calling this every step does not re-resolve::

ee = sess.read(obs, EEF_POS) img = sess.read(obs, Image(IMAGE_PRIMARY, layout=“hwc”))

The value is typed Any (like Reader’s): its concrete shape is the leaf’s declared encoding, which the caller owns.

observation_roles

function[source]
observation_roles()

The observation roles this session’s env declares, grouped by kind.

Connects if needed, reads the env contract’s published tags, and returns their observation_roles. An env that publishes no tags yields empty groups – “none declared” is an answer, not an error.

run

function[source]
run(
    *,
    seeds: Sequence[int] | None = None,
    episodes: int | None = None,
    max_episode_steps: int | None = None,
    max_episode_seconds: float | None = None,
    hooks: RunHooks | None = None,
    trial_index_base: int = 0,
)

Drive whole episodes to completion and return a typed RunResult.

The single drive loop: pumps this session’s own reset / predict / step primitives, so a served model’s run routes through here. episodes is the exact number of episodes to run (see resolve_episode_budget(): one by default, the length of seeds when only seeds are given, and the two must agree when both are). max_episode_steps / max_episode_seconds cap each episode – hitting a cap marks it truncated, exactly like the built-in step bound (the wall-clock cap is checked at the top of the step loop). Episode i walks trial ordinal trial_index_base + i, delivered as reset(options={"trial_index": ...}) to an env that declared the key in :attr:EnvFactory.reset_options \<rlmesh.EnvFactory.reset_options> (an env that did not never sees it) and recorded on EpisodeResult.trial either way; the base lets a local eval walk the same states as a platform shard. hooks (RunHooks) observes the loop; hook exceptions propagate and abort the run, and RunHooks.on_run_end() always fires exactly once with the completed episodes, even on an error or interrupt.

Does not close the session: a caller-held session (from rlmesh.session() / Model.session()) stays connected – viewer and hooks included – so run can be called again or mixed with manual driving; close it via close() or the with block. (The one-shot rlmesh.run() / Model.run() own their internal session and close it for you.)

close

function[source]
close()

Close this session: served route (and owned source), connection, env.

For a served model, closes the model client and shuts down a managed source it started (e.g. a SandboxModel container). For the env, shuts it down only on the close_env opt-in, and always releases what this session made itself: a connection it dialed or an env it built from a factory. A local model instance is the caller’s and is never closed here (one the session built from a class is closed exactly once).

A viewer with View.hold holds first, but only after a session that ended normally: when the last run() raised, or the with block is exiting on an exception (KeyboardInterrupt included), the hold is skipped so everything is released and the error propagates at once.

Idempotent: later calls are no-ops, and any other use of a closed session raises RuntimeError.