rlmesh.Session
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.)
Attributes
Methods
- reset()Begin a new episode: end the previous one, then reset the env and adapter.
- predict()Map one env observation to an env-ready action (the model's adapter applied).
- step()Apply one action to the env; record reward and termination.
- frame_sources()The env's image roles and
render()source, as the viewer sees them. - reader()Build a read-only, role-addressed view over this env's observations.
- read()One-shot read of a single role from one observation.
- observation_roles()The observation roles this session's env declares, grouped by kind.
- run()Drive whole episodes to completion and return a typed
RunResult. - close()Close this session: served route (and owned source), connection, env.
selected_workflow_edition
property[source]property selected_workflow_edition: strThe 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: boolWhether 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: AnyThe connected env’s contract (connects on first use).
num_envs
property[source]property num_envs: intLanes 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.