> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reasonblocks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FSMState: agent difficulty state enum

> Reference for the FSMState enum — the six states ReasonBlocks uses to classify per-step difficulty and trigger model routing, monitor injection cooldowns, and E-trace gating.

`FSMState` is the enum at the heart of ReasonBlocks' difficulty tracking. After scoring each reasoning step, the SDK advances a finite state machine through these states to determine model routing, monitor-injection cooldowns, and whether to skip the E-trace retrieval pipeline. You read the current state from `TraceState.current_state` and from per-step `StepLogEntry.fsm_state` fields exposed on the middleware.

```python theme={null}
from reasonblocks.types import FSMState
```

## States

| State    | Trigger condition (built-in FSM)                                                   | Behavior                                                                                                                                                                            |
| -------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INIT`   | Set at construction time                                                           | First `before_model` call transitions to `NORMAL`                                                                                                                                   |
| `FAST`   | Six consecutive scores below `fast_threshold` (0.2)                                | Skips the full E-trace retrieval pipeline; routes to the FAST-tier model when `model_routing` includes a `FAST` entry; monitors still evaluate. Monitor injection cooldown: 5 steps |
| `NORMAL` | Default operating state                                                            | E-trace pipeline runs, gated by the E1 retrieval gate. Monitor injection cooldown: 3 steps                                                                                          |
| `SLOW`   | Five consecutive scores above `slow_threshold` (0.6)                               | Routes to the SLOW-tier model when configured. Monitor injection cooldown: 2 steps                                                                                                  |
| `SKIP`   | Reached only from `SLOW` after 35 consecutive scores above `skip_threshold` (0.85) | Routing and cooldown identical to `SLOW`; signals an exceptionally stalled run for downstream tooling                                                                               |
| `END`    | Defined in the enum                                                                | Not entered by the built-in `DifficultyFSM`. Reserved for callers that ship a custom transition function                                                                            |

The default thresholds and windows live on `DifficultyFSM`; override them via `ReasonBlocks(fsm_thresholds={...})`.

## State reference

### `FSMState.INIT`

The trace starts in `INIT`. The first scored step transitions to `NORMAL`. You will only see `INIT` on the very first `before_model` call (before any thought has been produced).

### `FSMState.FAST`

Entered from `NORMAL` when the most recent six difficulty scores are all below `fast_threshold` (default `0.2`). In `FAST`, the middleware skips the full E-trace retrieval pipeline (`E1`, `E2`, `E3`); monitors still run so loop and trajectory-length detectors keep working. If `model_routing` contains a `FAST` entry, the next call uses that model.

### `FSMState.NORMAL`

The default state. The E-trace pipeline runs, with E1 retrieval further gated by recent monitor activity (see the [middleware notes](/api-reference/reasonblocks)). The model from your `ReasonBlocks` config is used unless `model_routing` overrides it for `NORMAL`.

### `FSMState.SLOW`

Entered from `NORMAL` when the most recent five difficulty scores all exceed `slow_threshold` (default `0.6`). E-traces continue to be retrieved; if `model_routing` contains a `SLOW` entry the next call swaps to that model.

<Note>
  Both `FAST` and `SLOW` exit on a single contrary score with hysteresis: from `FAST`, a score above `fast_threshold + hysteresis_margin` (0.3) returns to `NORMAL`; from `SLOW`, a score below `slow_threshold - hysteresis_margin` (0.5) returns to `NORMAL`.
</Note>

### `FSMState.SKIP`

Entered from `SLOW` when 35 consecutive scores all exceed `skip_threshold` (default `0.85`). For routing and monitor-injection cooldown purposes, `SKIP` is identical to `SLOW`; it is a separate label so dashboards and downstream code can flag exceptionally stalled runs. There is no special "skip injection" — the same monitor steering and E-trace machinery applies.

### `FSMState.END`

`END` is defined in the enum but the built-in `DifficultyFSM.transition` never returns it. The state exists for callers that supply a custom transition function that wants to mark a trace as terminal. Reading `END` from a stock SDK installation indicates manual intervention.

## Monitor injection cooldowns

Monitor steering injection respects per-state cooldowns to avoid over-steering. The middleware caps monitor injections at 5 per run total.

| State    | Cooldown (steps between monitor injections) |
| -------- | ------------------------------------------- |
| `FAST`   | 5                                           |
| `NORMAL` | 3                                           |
| `SLOW`   | 2                                           |
| `SKIP`   | 2                                           |

## Reading state after a run

```python theme={null}
from reasonblocks import ReasonBlocks

rb = ReasonBlocks(api_key="rb_live_...")

with rb.middleware(run_id="run-1", agent_name="bugfixer", task="...") as mw:
    result = agent.invoke({"messages": [("user", "Fix the failing tests.")]})

for entry in mw.step_log:
    print(entry.step, entry.fsm_state, entry.difficulty)
```

`StepLogEntry.fsm_state` is the string value of the enum (e.g. `"FAST"`, `"NORMAL"`); use `FSMState(entry.fsm_state)` to round-trip back to the enum.

## Values

`FSMState` is a standard `enum.Enum`. Each member's `.value` is its uppercase string name, which is also what appears in the dashboard.

```python theme={null}
FSMState.INIT.value    # "INIT"
FSMState.FAST.value    # "FAST"
FSMState.NORMAL.value  # "NORMAL"
FSMState.SLOW.value    # "SLOW"
FSMState.SKIP.value    # "SKIP"
FSMState.END.value     # "END"
```
