How to wait for a robot state

Copy Markdown View Source

Sometimes you want an agent action to block until the robot enters a particular state — for example, "wait until the robot is :idle before issuing the next move". This guide covers the two available patterns.

Option 1: BB.Jido.Action.WaitForState

The simplest case is a single, foreground wait. The action is on the agent already (the robot plugin attaches it). Send it via the default route:

:ok =
  Jido.AgentServer.cast(
    pid,
    Jido.Signal.new!(
      "bb.state.wait",
      %{robot: MyRobot, target: :idle, timeout: 5_000}
    )
  )

Return shapes:

OutcomeReturn
Robot already in target{:ok, %{robot: ..., state: target}}
Transitions into target within timeout{:ok, %{robot: ..., state: target}}
timeout elapses first{:error, :timeout}

The action subscribes to [:state_machine] for the duration of the wait and unsubscribes when it returns.

Caveat: this blocks the agent process while it waits. If your agent also needs to react to other signals during the wait, that processing is paused. For non-blocking waits, see Option 2.

Option 2: an event-driven decision

For long waits or concurrent waits, react to the transition signal instead. The robot plugin already forwards bb.state.transition signals into the agent; scaffold an action that pattern-matches on the payload:

mix bb_jido.add_action MyRobot.OnTransition
defmodule MyRobot.OnTransition do
  use Jido.Action,
    name: "on_transition",
    schema: [
      robot: [type: :atom, required: true],
      path: [type: {:list, :atom}, required: true],
      message: [type: :any, required: true]
    ]

  @impl Jido.Action
  def run(%{robot: robot, message: %BB.Message{payload: payload}}, _context) do
    case payload do
      %BB.StateMachine.Transition{to: :idle} -> handle_idle(robot)
      %BB.StateMachine.Transition{to: :error} -> handle_error(robot)
      _ -> {:ok, %{ignored: true}}
    end
  end
end

Attach via a plugin with signal_routes: [{"bb.state.transition", MyRobot.OnTransition}]. The agent stays responsive throughout — the action runs only when the transition actually happens, and only for the transitions you care about.

Rule of thumb: if the timeout is short (sub-second), Option 1 is fine. If it's seconds or more, prefer Option 2.

Pre-cached state on the plugin

BB.Jido.Plugin.Robot keeps a safety_state field in its plugin state that's updated whenever a transition signal arrives. Read it from another action via context.agent.state.robot.safety_state to skip a Runtime lookup. This is a convenience cache — BB.Robot.Runtime.state/1 is also cheap (ETS), so use whichever reads better in your code.

See also