Skip to main content
ReasonBlocks tracks each step’s difficulty through a finite state machine. By passing model_routing to the ReasonBlocks constructor, you can map any of the four post-INIT states (FAST, NORMAL, SLOW, SKIP) to a model identifier. The middleware swaps the model on the active ModelRequest inside wrap_model_call, before pattern injections render — so format-routing pattern selection sees the post-routing model family.
Model routing is opt-in. Without model_routing, the agent’s configured model runs every step.

How states map to routing

FAST is the only state that affects E-trace retrieval — it skips E1, E2, and E3 because the agent is sailing through. Monitor scoring still runs in FAST so loop detection stays active. Any state can be mapped or unmapped independently; unmapped states leave the agent’s configured model untouched.

Configure routing

Keys must match FSMState names: "FAST", "NORMAL", "SLOW", "SKIP". Values follow LangChain’s init_chat_model format ("provider:model-name").
You don’t have to map every state. Omit any you don’t want to override:
The middleware caches resolved chat models per id (init_chat_model is called once per unique id and reused).

Inspect routing decisions

StepLogEntry.model_id holds the resolved model id when routing fired on that step. Steps with no routing override leave it empty.
Sample output:

Tune the FSM thresholds

Pass fsm_thresholds to adjust when routing transitions happen. See Advanced configuration for the full set of knobs and the hysteresis rule that prevents thrashing at boundaries.
Lowering fast_threshold keeps the agent on the cheap model longer. Raising slow_threshold delays escalation. Either change reduces cost; both can affect quality on genuinely hard work.