Info dict contract#
Every TorchWM environment adapter and wrapper guarantees a minimum set of keys in the info dict returned by step(). Downstream code (value models, replay buffers, logging) may rely on these keys being present.
Universally guaranteed keys#
The function finalize_step_info() in world_models.envs._contract normalises every step() return. These three keys are always present:
Key |
Type |
Description |
|---|---|---|
|
|
The episode ended because the task reached a terminal state (goal reached, failure, etc.). |
|
|
The episode ended because of an external limit (time horizon, max steps, etc.). |
|
|
Discount factor for the transition. |
Important: GymImageEnv without a wrapping TimeLimit sets discount=0.0 on any done=True return, including truncation, because it treats all terminal transitions the same way. Wrap with TimeLimit to get discount=1.0 on time-limit truncations (the Dreamer wrapper stack does this automatically). The cross-backend contract tests in tests/envs/test_env_contract.py (test_env_contract_shared_assertions) verify this behavior for each backend adapter.
obs, reward, terminated, truncated, info = env.step(action)
# info always contains:
assert "terminated" in info
assert "truncated" in info
assert "discount" in info
Commonly guaranteed keys#
All backends except WorldModelEnv and DiamondAtari (passthrough) set these keys:
Key |
Type |
Description |
|---|---|---|
|
|
The action as seen by the policy after normalisation / one-hot encoding. |
|
|
The action actually sent to the underlying environment before normalisation. For discrete actions this is the integer index; for continuous actions it is the raw float array. This value can be stored and replayed identically even when the policy maps normalised actions. |
Per-backend keys#
DeepMind Control Suite (dmc.py)#
Key |
Always? |
Description |
|---|---|---|
|
Yes |
Concatenated float array of all non-visual sensor values from the DMC |
Gym / Gymnasium (gym_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
No |
Present only when the wrapped environment exposes non-visual observations that can be meaningfully flattened (detected by |
Brax (brax_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
Yes |
Raw |
Dynamic keys |
No |
Every key present in |
MuJoCo (mujoco_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
Yes |
Concatenated non-visual sensor values. |
|
Yes |
Current simulation time from |
|
|
Joint positions. |
|
|
Joint velocities. |
Unity ML-Agents (unity_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
No |
Present only when the Unity environment provides non-visual observations. |
|
No |
|
DeepMind Lab (dmlab.py)#
Key |
Always? |
Description |
|---|---|---|
|
Yes |
The raw native action array from DeepMind Lab (before one-hot encoding). |
BSuite (bsuite_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
Yes |
Flattened observation array from the BSuite environment. |
|
Yes |
The string identifier of the BSuite task (e.g. |
Atari / Diamond (diamond_atari.py)#
Key |
Always? |
Description |
|---|---|---|
|
No |
|
Procgen (procgen_env.py)#
Key |
Always? |
Description |
|---|---|---|
Upstream keys |
No |
All keys from the underlying Procgen vector environment (for env index |
World Model (world_model_env.py)#
Key |
Always? |
Description |
|---|---|---|
|
No |
The full next state dict from the world model transition; set via |
|
No |
Number of steps taken inside the |
Wrapper-added keys#
Wrapper |
Key |
Always? |
Description |
|---|---|---|---|
|
(normalises |
Yes |
Overrides the terminated/truncated/discount from the wrapped environment according to the time-limit logic. See Environment Wrappers for details. |
|
|
Yes |
The number of times the action was actually repeated before the episode ended. |
|
|
Yes |
Stores the normalised action under |
Using info dict keys#
Logging and debugging#
obs, reward, terminated, truncated, info = env.step(action)
logger.store(reward=reward, terminated=terminated, truncated=truncated)
# MuJoCo-specific
if "qpos" in info:
logger.store(qpos=info["qpos"])
Replay buffers#
Always store info["action"] and info["executed_action"] together so the policy update can reconstruct the exact action that was sent to the environment:
transition = dict(
obs=obs,
action=info.get("action"),
executed_action=info.get("executed_action"),
reward=reward,
terminated=terminated,
truncated=truncated,
discount=info["discount"],
)
Value-function bootstrapping#
The discount key controls whether the value of the next state is bootstrapped:
if terminated:
target = reward
elif truncated:
target = reward + info["discount"] * next_value # bootstrap normally
else:
target = reward + info["discount"] * next_value
Note that discount is 0.0 for absorbing terminal states (so the bootstrap term is zero), but 1.0 for non-terminal transitions and typically also 1.0 for truncated transitions (the discount is applied after multiplying with discount).