Skip to main content

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.

Components are the primary extension mechanism in Foundation. Each Component class (a subclass of BaseComponent) bundles together a discrete action space, additional agent state fields, per-step dynamics, observations, and action masks into a single reusable module. When you construct an environment, you pass an ordered list of ("ComponentName", {kwargs}) tuples. The framework instantiates each component with a reference to the shared World object and calls its methods at the appropriate point in the episode loop.

Key class attributes

Every component class declares these class-level attributes:
class Build(BaseComponent):
    name = "Build"               # unique registry key
    component_type = "Build"     # optional shorthand (may be shared)
    agent_subclasses = ["BasicMobileAgent"]  # which agent types participate
    required_entities = ["Wood", "Stone", "Coin", "House", "Labor"]
component_type is used as a shorthand when looking up the component via env.get_component(shorthand) and when labelling dense log entries.

Required methods

get_n_actions(agent_cls_name)

Returns how many actions this component contributes for agents of the given type.
  • None — no actions for this agent type
  • int — a single action subspace with that many actions (not counting NO-OP)
  • list of (name, int) — multiple named subspaces (used for the planner’s per-agent tax actions)
# Gather component: 4 movement directions for mobile agents
def get_n_actions(self, agent_cls_name):
    if agent_cls_name == "BasicMobileAgent":
        return 4  # up, down, left, right
    return None

get_additional_state_fields(agent_cls_name)

Returns a {field: reset_value} dict of extra fields this component adds to agent.state. These fields are reset to reset_value at the start of every episode.
def get_additional_state_fields(self, agent_cls_name):
    # WealthRedistribution adds nothing
    return {}

component_step()

Called once per timestep (in the listed order of components) after actions have been parsed. This is where the component applies its dynamics to the world and agent state.
# WealthRedistribution: evenly split all coin among mobile agents
def component_step(self):
    world = self.world
    ic = [agent.state["inventory"]["Coin"] for agent in world.agents]
    ec = [agent.state["escrow"]["Coin"] for agent in world.agents]
    tc = np.sum(ic) + np.sum(ec)
    target_share = tc / self.n_agents
    for agent in world.agents:
        agent.state["inventory"]["Coin"] = float(target_share - ec[agent.idx])

generate_observations()

Returns a {agent.idx: obs_dict} dictionary. Called each step; the environment merges these observations with those from the scenario. An agent index may be omitted if the component has nothing new to report for that agent.
def generate_observations(self):
    # Return empty dict if the component adds no observations
    return {}

generate_masks(completions=0)

Returns a {agent.idx: mask} dictionary. Each mask is a binary numpy array aligned with the component’s action subspace (excluding NO-OP). A 1 means the action is valid; 0 means it is forbidden. The default implementation (in BaseComponent) enables all actions for all agents.
def generate_masks(self, completions=0):
    masks = {}
    for agent in self.world.agents + [self.world.planner]:
        n_actions = self.get_n_actions(agent.name)
        if n_actions is None:
            continue
        if isinstance(n_actions, (int, float)):
            masks[agent.idx] = np.ones(int(n_actions))
        elif isinstance(n_actions, (tuple, list)):
            masks[agent.idx] = {
                sub_name: np.ones(int(sub_n))
                for sub_name, sub_n in n_actions
            }
    return masks

Optional methods

additional_reset_steps()

Called during env.reset() after agent state fields have been reset. Use it to clear internal trackers such as lists of builds or trade orders.

get_metrics()

Returns a {"metric_key": scalar} dict of episode-level statistics contributed by this component. The environment prefixes these with "{component_type}/" in the combined metrics report.

get_dense_log()

Returns extra data for dense logging. Return None to opt out (default).

Composing components in a scenario

Components are listed in the components constructor argument. The component_set class attribute on built-in scenario classes shows a recommended default pairing:
env = foundation.scenarios.get("uniform/simple_wood_and_stone")(
    components=[
        ("Gather",  {"move_labor": 1.0, "collect_labor": 2.0}),
        ("Build",   {"payment": 10, "skill_dist": "pareto"}),
        ("ContinuousDoubleAuction", {"max_bid_ask": 10}),
        ("PeriodicBracketTax", {}),
    ],
    n_agents=10,
    world_size=[25, 25],
)
Ordering matters. Components are stepped and observed in the order they are listed. WealthRedistribution must always be last because it re-distributes whatever coin remains after all other components have run.

Built-in components

Allows BasicMobileAgent instances to move in four cardinal directions and automatically collect resources when landing on a resource tile.
  • Actions: 4 (up, down, left, right) per mobile agent
  • Required entities: Coin, House, Labor
  • Key args: move_labor (labor cost per move), collect_labor (labor cost per collection), skill_dist ("none" | "pareto" | "lognormal")
Allows mobile agents to spend Wood and Stone to place a House landmark at their current tile, earning Coin income.
  • Actions: 1 (build) per mobile agent
  • Required entities: Wood, Stone, Coin, House, Labor
  • Key args: payment (base Coin earned), payment_max_skill_multiplier, skill_dist, build_labor
Implements a commodity-exchange-style order book. Agents submit bids (buy orders) and asks (sell orders) for collectible resources; matching orders clear automatically.
  • component_type: "Trade"
  • Required entities: Coin, Labor
  • Key args: max_bid_ask (max price in Coin), order_labor, order_duration, max_num_orders
Passive component that evenly splits all mobile-agent Coin at the end of each timestep. No action space. Must be listed last.
  • Required entities: Coin
Periodically collects marginal income taxes from mobile agents and redistributes as lump-sum transfers. The planner sets the tax bracket rates.
  • Required entities: Coin
  • Agent subclasses: BasicMobileAgent, BasicPlanner
Adds 100 labor-level actions to mobile agents. Each action represents the number of hours worked; income equals hours × skill.Intended for use with PeriodicBracketTax and the one-step-economy scenario.
  • Actions: 100 per mobile agent
  • Required entities: Coin
  • Key args: mask_first_step, payment_max_skill_multiplier, pareto_param
Two components designed for the CovidAndEconomySimulation scenario:
  • ControlUSStateOpenCloseStatus — allows US-state agents (mobile) to select a pandemic-policy stringency level. Actions: n_stringency_levels per mobile agent.
  • FederalGovernmentSubsidy — allows the planner to set per-state direct-payment subsidies.

Build docs developers (and LLMs) love