BaseEnvironment is the abstract base class that all Foundation scenario environments extend. It instantiates the world, agents, and component objects, and exposes a Gym-style API for resetting, stepping, and seeding the environment.
BaseEnvironment is abstract and cannot be instantiated directly. Create a concrete scenario by subclassing it and implementing all required abstract methods, or use a scenario from foundation.scenarios.Class attributes
Subclasses must declare the following class-level attributes before any instance is created.str
required
Unique string identifier for the scenario. Used to register and retrieve the class from the scenario registry (
foundation.scenarios). Must be set to a non-empty string by every subclass.list
required
List of agent subclass name strings that this scenario applies to. Must contain at least one entry. When multiple subclasses are listed, none may be a subclass of another (no inheritance conflicts).
list
required
List of entity names (resources, landmarks, endogenous variables) that the scenario requires. May be an empty list. Coin and Labor are always included automatically.
Constructor
Parameters
list
required
A list specifying which components to include in the environment. Each element must be either:
- A tuple
("Component Name", {component_kwargs}) - A dict
{"Component Name": {component_kwargs}}
"Component Name" must match a name registered in the component registry. Reset, step, and observation generation are executed in the order components appear in this list — reordering can affect environment dynamics.int
required
Number of mobile agents. Does not include the planner. Must be an integer greater than or equal to 2.
list
required
A length-2 list
[height, width] specifying the dimensions of the 2D world map.int
default:"1000"
Number of timesteps in a single episode. Must be at least 1.
bool
default:"False"
When
True, mobile agents may choose one action per action subspace (defined by each component) per timestep. When False, all subspaces are concatenated into a single action space and agents choose one action from the aggregate.bool
default:"True"
Same as
multi_action_mode_agents but for the planner agent.bool
default:"True"
When
True, all scalar and vector observation subfields are concatenated into a single "flat" observation field before being returned. When False, observations are returned as minimally processed dictionaries.bool
default:"True"
When
True, action masks are concatenated into a single flat array. When False, masks are returned as a {"action_subspace_name": mask} dictionary. Set to True for deep RL action masking — flattened masks have the same semantics as policy logits.bool
default:"True"
When
True, certain observation fields (e.g. inventory) are scaled to a range better suited for deep RL training.int | None
default:"None"
How often (in completed episodes) to create a dense log.
None disables automatic dense logging. Set to e.g. 20 to log every 20th episode. Dense logs record agent states, actions, and rewards at each timestep, and world map snapshots at a coarser cadence.int
default:"50"
When dense logging is active, how often (in timesteps) to snapshot the world state. More frequent snapshots increase memory usage.
bool
default:"False"
When
True, observations, rewards, and info dictionaries from all mobile agents ("0", "1", …) are collated into a single entry keyed by "a". Useful for GPU-accelerated training with WarpDrive.int | float
default:"None"
If provided, sets both the numpy and Python built-in RNG seeds at construction time. Must be greater than 0. Can also be set later via
env.seed(seed).Properties
world
World object that holds the world map and all agent objects. Constructed during __init__ once all entities and components have been registered.
all_agents
env.world.agents + [env.world.planner].
episode_length
n_agents
components
resources
"Coin".
landmarks
endogenous
"Labor".
metrics
scenario_metrics()) and all components (component.get_metrics()). Component metrics are namespaced as "<component_shorthand>/<metric_key>".
previous_episode_metrics
None before the first episode finishes.
dense_log
"world", "states", "actions", "rewards", plus optional per-component keys.
previous_episode_dense_log
previous_episode_replay_log
"reset" and "step" keys that together allow the exact episode to be reproduced.
inv_scale
0.01 when allow_observation_scaling=True, otherwise 1.
Methods
reset()
reset_starting_layout(), reset_agent_states(), each component’s reset(), and additional_reset_steps() in order. Returns initial observations.
Parameters
tuple | list
default:"None"
Optional numpy RNG state to restore before resetting. Must be length 5, in the format expected by
np.random.set_state(). Used for deterministic episode replay.bool
default:"False"
When
True, forces dense logging to be active for this episode regardless of dense_log_frequency.Returns
dict
A dictionary
{"agent_idx": agent_obs} with one entry per agent. Keys match each agent’s agent.idx property. Values are observation dictionaries (flattened to a "flat" key when flatten_observations=True). Includes an "action_mask" field for each agent.step()
Parameters
dict
default:"None"
Dictionary
{agent_idx: action} mapping each acting agent’s index to its chosen action.- When
agent.multi_action_modeisTrue:actionmust be a list of integers, one per action subspace. - When
agent.multi_action_modeisFalse:actionmust be a single integer selecting from the concatenated action space.
None, all agents take the NO-OP action.tuple | list
default:"None"
Optional numpy RNG state to restore before stepping. Must be length 5. Used for deterministic episode replay.
Returns
dict
Observation dictionary with the same structure as returned by
reset().dict
Dictionary
{"agent_idx": reward} with one scalar reward per agent. Keys match those in obs.dict
Dictionary with a single key
"__all__". Value is False while world.timestep < episode_length, and True when the episode ends.dict
Placeholder dictionary
{"agent_idx": {}} with the same keys as obs and rew.seed()
Parameters
int | float
required
Seed value. Must be greater than 0. Float values are cast to
int internally.get_component()
Parameters
str
required
Full name or shorthand name of the component to retrieve. Must correspond to a component registered in this environment instance. Raises
KeyError if no match is found.Returns
BaseComponent
The component object instance wrapped in the environment.
get_agent()
Parameters
int | str
required
Identifier matching the
idx property of the desired agent. The planner’s index is "p". Raises ValueError if no agent with the given index exists.Returns
BaseAgent
The agent object with the corresponding index.
set_agent_component_action()
parse_actions().
Parameters
int | str
required
Index of the agent whose action to set.
str
required
Name of the action subspace to set the action for.
int
required
Integer index of the chosen action within the named subspace.
parse_actions()
{agent_idx: action} dictionary and load the actions into each agent’s action buffer.
Parameters
dict
required
Dictionary mapping agent indices to their chosen actions. Same format as the
actions argument of step().Abstract methods
Every concrete scenario subclass must implement the following methods.reset_starting_layout()
reset_agent_states()
scenario_step()
step() after all component steps and before observation/reward generation. Implement resource regeneration, income redistribution, and similar rules here.
generate_observations()
Returns
dict
Dictionary
{agent.idx: agent_obs_dict} with one entry for each agent type this scenario provides observations for.compute_reward()
Returns
dict
Dictionary
{agent.idx: scalar_reward} with one float reward per agent, including the planner.Optional override methods
additional_reset_steps()
reset_starting_layout(), reset_agent_states(), and each component’s reset(). Override to perform any final scenario-specific initialization.
scenario_metrics()
{metric_key: scalar_value} dictionary of scenario-specific metrics. These are merged with component metrics and exposed via the metrics property. Return None (the default) to contribute no metrics.
Scenario registry
Thescenario_registry is a Registry object that maps scenario names to their classes. Decorate a subclass with @scenario_registry.add to register it.
The
foundation package exposes the scenario registry as foundation.scenarios. A scenario registered in the above way is only visible through foundation.scenarios if its module is imported in ai_economist/foundation/scenarios/__init__.py.