Components define the interactive dynamics of an environment. They expand agent action spaces, inject observations, and implement the rules that govern what happens when an agent acts. Any mechanic that does not belong to the scenario’s passive world logic—movement, trading, building, taxation—belongs in a component. Create a custom component when you need agents to perform a new type of action or when you want to add side-channel observations and metrics without modifying an existing scenario.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/salesforce/ai-economist/llms.txt
Use this file to discover all available pages before exploring further.
How components fit into the environment
When aBaseEnvironment subclass is instantiated, each component in the components list is constructed and wired into the environment. At every timestep the environment calls each component in order:
component_step()— execute action effectsgenerate_observations()— collect per-component observationsgenerate_masks()— produce action validity masks
additional_reset_steps() is called so stateful components can reinitialise their internal bookkeeping.
The Gather component: a worked example
Before writing your own component, read through theGather component (ai_economist/foundation/components/move.py). It is the canonical reference implementation.
move.py
Step-by-step: implementing a custom component
Subclass BaseComponent and set class attributes
Every component must declare four class-level attributes before
__init__ is called:| Attribute | Type | Purpose |
|---|---|---|
name | str | Unique identifier used by the registry. Must not contain .. |
component_type | str or None | Optional shorthand (e.g. "Trading"). Used when looking up via env.get_component(). |
agent_subclasses | list[str] | Agent class names this component interacts with. Must be non-empty. |
required_entities | list[str] | Resources, landmarks, or endogenous variables this component expects to exist in the world. |
agent_subclasses must list concrete agent names (e.g. "BasicMobileAgent", "BasicPlanner"), not base class names. If you list more than one, none of them may be a subclass of another.Implement __init__
Accept your custom kwargs before passing
*base_component_args and **base_component_kwargs to super().__init__().After super().__init__() you can access:self.world— theWorldobject (maps + agents + planner)self.n_agents— number of mobile agentsself.resources/self.landmarks— lists of entity namesself.episode_length— total timesteps per episodeself.inv_scale— shared inventory scaling factor for observations
Implement get_n_actions
Tell the environment how many actions (excluding NO-OP) this component adds for each agent type.For a planner that sets per-agent tax levels across
n agents with k brackets:Implement get_additional_state_fields
Declare any extra keys that should live in
agent.state and their reset values. The environment calls this during construction and again at every reset.Implement component_step
Apply the effects of each agent’s chosen action. This is called once per timestep, after all component steps in the list before yours have run.Access the agent’s chosen action with
agent.get_component_action(self.name). Action index 0 is always NO-OP.Implement generate_observations
Return a dict of
{agent_idx: obs_dict}. Only include agents for which this component provides observations. The structure must stay consistent across timesteps.Return string keys (
str(agent.idx)) so that the environment’s observation collation works correctly.Implement generate_masks
Return a binary mask dict indicating which actions are valid. The mask length must equal the number of non-NO-OP actions. NO-OP is always valid and must not appear in the mask.The base class provides a sensible default (all actions valid). Override only when you need to restrict actions based on state.For multi-action-space planners, return a nested dict:
Implement additional_reset_steps (optional)
Reset any internal state that persists across timesteps. Called automatically during For
env.reset().Looking at Gather for reference:BonusOutput:Registering the component
Decorating the class with@component_registry.add registers it under component.name:
Complete minimal example
bonus_output.py