> ## Documentation Index
> Fetch the complete documentation index at: https://salesforce-ai-economist.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Components

> How Components extend environment dynamics by defining action spaces, state fields, per-step logic, observations, and masks.

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:

```python theme={null}
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)

```python theme={null}
# 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.

```python theme={null}
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.

```python theme={null}
# 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.

```python theme={null}
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.

```python theme={null}
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:

```python theme={null}
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],
)
```

> [!WARNING]
>
> 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

> **Gather (move.py)**
>
> 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"`)

> **Build (build.py)**
>
> 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`

> **ContinuousDoubleAuction (continuous\_double\_auction.py)**
>
> 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`

> **WealthRedistribution (redistribution.py)**
>
> 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`

> **PeriodicBracketTax (redistribution.py)**
>
> 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`

> **SimpleLabor (simple\_labor.py)**
>
> 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`

> **COVID-19 components (covid19\_components.py)**
>
> 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.