Skip to content

Hierarchical State Machine (HSM) Infrastructure

The agent-utilities graph orchestrator implements a Hierarchical State Machine (HSM) and Behavior Tree (BT) hybrid model via agent_utilities.graph.hsm.

This module provides the necessary primitives for running complex parallel workflows, tracking agent lifecycles, and guarding state invariants during graph transitions.

Core Features

1. Orthogonal Regions (Concurrency)

Orthogonal regions allow an agent to run multiple independent sub-state-machines in parallel within a single superstate. This is implemented via run_orthogonal_regions.

When a task requires multiple sub-tasks (e.g. scanning multiple directories, fetching data from multiple APIs), the orchestrator can fan-out queries to the same specialist agent concurrently and merge the results:

from agent_utilities.graph.hsm import run_orthogonal_regions

queries = [
    "Scan frontend/src for React components",
    "Scan backend/app for FastAPI routes"
]

# Runs both queries concurrently against the same agent
results = await run_orthogonal_regions(
    agent=my_specialist_agent,
    queries=queries,
    deps=ctx.deps,
    timeout=120.0,
    event_queue=ctx.deps.event_queue,
    agent_name="CodeScanner"
)

# Results is a dict mapping query -> output

2. Entry & Exit Hooks

The HSM module allows registering global plugin hooks that fire whenever the graph enters or exits a specialist node. This is heavily used for streaming events, telemetry, and duration tracking.

from agent_utilities.graph.hsm import register_on_enter_hook, register_on_exit_hook

async def my_entry_plugin(deps, state, agent_name, server_name):
    print(f"Entering specialist: {agent_name}")

async def my_exit_plugin(deps, state, agent_name, success, server_name, duration):
    print(f"Exited specialist: {agent_name} in {duration}s. Success: {success}")

register_on_enter_hook(my_entry_plugin)
register_on_exit_hook(my_exit_plugin)

3. State Invariant Guards

To prevent the graph from entering infinite loops, corrupting its cursor, or losing its primary objective, assert_state_valid checks invariants at every transition boundary.

from agent_utilities.graph.hsm import assert_state_valid, StateInvariantError

try:
    assert_state_valid(ctx.state, transition="Planner -> Dispatcher")
except StateInvariantError as e:
    # State is corrupt! Triggers automatic recovery/fallback.
    logger.error(f"Graph corruption: {e}")

4. Static Routing (Junction Pseudostates)

Before falling back to the heavy LLM Router, the HSM attempts to use static_route_query. This function scans the query for exact keyword matches against known specialists.

If a user explicitly types "list gitlab projects", the static router bypasses the LLM layer entirely and routes directly to the GitLab specialist, saving latency and token costs.

from agent_utilities.graph.hsm import static_route_query

available_specialists = {
    "gitlab_api": "GitLab API interactions",
    "python_coder": "Writes python code"
}

# Returns "gitlab_api" based on exact keyword match
target = static_route_query("Please list gitlab projects", available_specialists)

5. Behavior Tree Results

Nodes return specific states to indicate their execution status, mirroring Behavior Tree paradigms:

  • NodeResult.SUCCESS: The specialist completed its task successfully. Move to the next plan step.
  • NodeResult.FAILURE: The specialist failed or circuit broke. Trigger error recovery or re-plan.
  • NodeResult.RUNNING: The node is suspended (e.g. waiting for human-in-the-loop approval).