State Machines

By the Syncfusion DevTutorials team · Last updated

The named states an agent moves through, the rules for moving between them, how to check a run for illegal moves, how to recover from failure, and how to see it all.

Think about a traffic light.

A traffic light can be in only one of three states: green, yellow, or red.

It can move from green to yellow and from yellow to red.

However, it cannot jump directly from green to red. Everyone on the road understands these rules, so the traffic light behaves in a predictable way.

A traffic light is a state machine. It has a set of named states and clear rules that define how it can move from one state to another.

An agent works in a similar way. At any moment, the agent is in a specific state, such as "thinking" or "waiting for a tool result." Rules determine which state it can move to next.

The main idea: A state machine gives an agent a set of named states and clear transition rules. This makes it easier to understand what the agent is doing and identify actions that should never happen.

A Real-World Example

Think about ordering food through a delivery app. Your order moves through different statuses:

  1. Placed: The restaurant has received your order.
  2. Cooking: The restaurant is preparing your food.
  3. On the way: A driver is delivering your order.
  4. Delivered: The order has arrived at your location.

An order cannot move directly from Placed to Delivered without being prepared and sent out for delivery.

If the app ever showed that sequence, you would immediately know that something was wrong.

An agent run also moves through a series of states. Viewing those states step by step helps you understand how the agent works and makes debugging easier.

In simple words: A state is what the agent is doing right now. A state machine is the collection of states and the rules that control how the agent moves between them.

What You Will Learn

In this lesson, you will learn:

  1. The five main agent states: Idle, Reasoning, Action, Waiting, and Completion.
  2. How transition rules determine which state can come next.
  3. How to identify invalid state transitions during a run.
  4. How an agent handles and recovers from failures.
  5. How to view and track states using diagrams and debugging tools.

The Agent Lab includes a States tab. After each run, it displays every state the agent moved through and verifies that each transition followed the defined rules. The examples in this lesson include a successful run, a failure with recovery, and a run that reaches its step limit.

Agent States

A state is a named stage that represents what the agent is currently doing. An agent can be in only one state at a time.

The agent states and their allowed transitions. The agent can cycle through Reasoning, Action, and Waiting multiple times until it reaches Completion or Failed.

Idle State

Idle means the agent has not started working yet. It has received a goal but has not performed any actions.

Every agent run starts in the Idle state.

Reasoning State

Reasoning means the agent is deciding what to do next. This is the stage where the model is called and determines the next action.

This is often the slowest and most expensive state because it uses the AI model.

Action State

Action means the agent has selected a tool and is preparing to use it.

At this stage, the application verifies:

  • The tool name
  • The tool inputs
  • Any boundaries or permissions

before the tool is allowed to run.

Waiting State

Waiting means the tool is currently running and the agent is waiting for the result. For example, running tests or sending a web request may take several seconds.

The agent should not make any decisions while it is waiting because it does not yet have the result.

Completion State

Completion means the agent reached its goal and stopped. No additional actions occur after the Completion state.

In practical systems, there is also another important state called Failed.

Failed means something prevented the agent from completing its task, such as:

  • A system error
  • A tool failure
  • Reaching the step limit

A failure does not always mean the run is over. In many cases, the agent can recover and continue.

The next example lists the available states and the rules for moving between them. It then tests five different state transitions.

States and the rules for moving between them

const rules = {
  Idle: ["Reasoning"],
  Reasoning: ["Action", "Completion", "Failed"],
  Action: ["Waiting", "Failed"],
  Waiting: ["Reasoning", "Failed"],
  Failed: ["Reasoning"],
  Completion: [],
};

function canMove(from, to) {
  return rules[from].includes(to);
}

const tries = [
  ["Idle", "Reasoning"],
  ["Reasoning", "Action"],
  ["Idle", "Completion"],
  ["Waiting", "Reasoning"],
  ["Completion", "Reasoning"],
];

for (const [from, to] of tries) {
  console.log(from + " -> " + to + ": " + (canMove(from, to) ? "allowed" : "NOT allowed"));
}

Expected output:

Idle -> Reasoning: allowed
Reasoning -> Action: allowed
Idle -> Completion: NOT allowed
Waiting -> Reasoning: allowed
Completion -> Reasoning: NOT allowed

Idle cannot move directly to Completion because the agent has not done any work yet. In the same way, no state can come after Completion because the run has already finished.

Now watch a real run. Click Run it, then open the States tab.

A Clean Run Through the States

You will see the agent move through the states in order. It starts in Idle, then moves through Reasoning, Action, and Waiting for each tool it uses, and finally reaches Completion.

The States tab also reports that all state transitions were valid.

State Transitions

A transition is a move from one state to another. Many agent-related issues happen because the agent moves to a state that it should never enter.

Transition Rules

Transition rules define which state changes are allowed. In the previous example, the rules object acts as a transition table. Each state contains a list of states that are allowed to come next.

It is a good practice to define these rules before building the agent. The rules act as a contract that describes how the agent is expected to behave.

State Validation

State validation is the process of checking whether a run followed the transition rules. To validate a run, compare the recorded states one pair at a time. Every transition must match one of the allowed rules.

If even one transition is not allowed, the agent has entered an impossible state. This indicates a bug in the agent application, even if the final result appears to be correct.

Check a recorded run for illegal moves

const rules = {
  Idle: ["Reasoning"],
  Reasoning: ["Action", "Completion", "Failed"],
  Action: ["Waiting", "Failed"],
  Waiting: ["Reasoning", "Failed"],
  Failed: ["Reasoning"],
  Completion: [],
};

function validate(run) {
  for (let i = 1; i < run.length; i++) {
    if (!rules[run[i - 1]].includes(run[i])) return "Illegal move: " + run[i - 1] + " -> " + run[i];
  }
  return "Valid run";
}

const good = ["Idle", "Reasoning", "Action", "Waiting", "Reasoning", "Completion"];
const bad = ["Idle", "Reasoning", "Action", "Reasoning", "Completion"];

console.log(validate(good));
console.log(validate(bad));

Expected output:

Valid run
Illegal move: Action -> Reasoning

The bad run skipped the Waiting state. The agent selected a tool and then started reasoning again without waiting for the result.

This usually means the tool result was lost or never returned to the agent.

State Recovery

State recovery is the process of returning the agent to a working state after a failure.

Not every failure means the run must end.

For example, if a test runner crashes once, the problem is with the tool, not necessarily with the agent's answer. In that situation, the agent can move from the Failed state back to the Reasoning state and try a different approach.

However, recovery should always have limits.

An agent that keeps retrying forever is not recovering. It is stuck in a loop.

A good recovery system allows the agent to try again a limited number of times and then stop if the problem cannot be resolved.

Recover from a crash, but only a few times

function runWithRecovery(crashes, maxRetries) {
  const states = ["Idle"];
  let retries = 0;
  for (let attempt = 1; attempt <= crashes + 1; attempt++) {
    states.push("Reasoning", "Action", "Waiting");
    if (attempt <= crashes) {
      states.push("Failed");
      if (retries === maxRetries) return states.join(" > ") + " (gave up)";
      retries++;
      continue;
    }
    states.push("Reasoning", "Completion");
    return states.join(" > ");
  }
}

console.log(runWithRecovery(1, 2));
console.log(runWithRecovery(3, 2));

Expected output:

Idle > Reasoning > Action > Waiting > Failed > Reasoning > Action > Waiting > Reasoning > Completion
Idle > Reasoning > Action > Waiting > Failed > Reasoning > Action > Waiting > Failed > Reasoning > Action > Waiting > Failed (gave up)

If there is 1 crash, the agent recovers and completes the task successfully. If there are 3 crashes and only 2 retries are allowed, the agent stops and reports a failure.

Stopping is the correct behavior in that situation. It prevents the agent from wasting time and steps on a tool that is not working.

Now watch a recovery in the Agent Lab. In this example, the first test run is designed to crash.

A Crash, Then Recovery

Step 1 shows the crash. In the States tab, you will see the agent move from Waiting to Failed, and then back to Reasoning. The agent's reasoning explains why it continues: "That is a tool failure, not a test result."

Easy Way to Remember: An agent usually repeats think, act, wait. It eventually ends in Completion or Failed. When recovery is possible, the agent moves from Failed back to Reasoning and tries again.

State Visualization

State information is only useful if you can see and understand it. There are three common ways to visualize agent states.

Flow Diagrams

A flow diagram displays states as boxes and transitions as arrows between them. The diagram shown at the beginning of this lesson is an example of a flow diagram.

Creating a flow diagram before building an agent helps you identify missing transitions early.

For example, you might ask: "What should happen if a tool times out while the agent is in the Waiting state?"

Thinking about these situations in advance helps create a more reliable agent.

Runtime Tracking

Runtime tracking means recording the agent's current state at every step while it is running. It answers questions like "how many steps were spent Reasoning?"

Count how long the agent spent in each state

const run = ["Idle", "Reasoning", "Action", "Waiting", "Reasoning", "Action", "Waiting", "Waiting", "Waiting", "Reasoning", "Completion"];

const counts = {};
for (const state of run) {
  counts[state] = (counts[state] || 0) + 1;
}

for (const [state, n] of Object.entries(counts)) {
  console.log(state + ": " + n);
}

Expected output:

Idle: 1
Reasoning: 3
Action: 2
Waiting: 4
Completion: 1

Waiting appears 4 times, more than any other state. In a real agent, that would suggest that a tool is taking a long time to respond. Improving the speed of that tool could significantly improve the overall speed of the agent.

Debug Views

A debug view displays the state history in a format that is easy for people to read and understand. It often marks the current state, and highlights failures.

A simple debug view of a run

function debugView(run) {
  return run
    .map((state, i) => {
      const mark = i === run.length - 1 ? "[" + state + "]" : state;
      return state === "Failed" ? mark + "!" : mark;
    })
    .join(" > ");
}

console.log(debugView(["Idle", "Reasoning", "Action", "Waiting", "Failed", "Reasoning"]));

Expected output:

Idle > Reasoning > Action > Waiting > Failed! > [Reasoning]

The brackets show the agent's current state. The ! symbol marks a failure. With a quick look, you can see that the agent failed once and then returned to thinking.

The States tab in the Agent Lab is an example of a debug view. Now look at a run that does not finish successfully. The step limit is set to 3, which is not enough for this task.

Out of Steps

The final state is Failed, not Completion. The agent modified the file, but it never had the chance to verify whether the change worked. Any run that ends in Failed should never be considered successful.

Only a run that reaches Completion has successfully achieved its goal. A run that ends in any other state, even if the output looks correct, should be treated as a failure.

Common Mistakes

MistakeIncorrect UnderstandingCorrect UnderstandingWhat Can Go Wrong
No documented transition rules"The agent will automatically know what to do next."Create and follow a transition table.Invalid state transitions can occur without being noticed.
Skipping the Waiting state"The tool runs quickly, so there is no need to wait."Always wait for the result before making another decision.The agent makes decisions without having the required information.
Unlimited recovery attempts"Just keep retrying until it works."Retry a limited number of times, then stop if the issue continues.The agent wastes all its steps on a failing tool.
Treating Failed as success"The agent stopped, so it must be finished."Only the Completion state means the goal was achieved.An unsuccessful result may be reported as a successful one.
No state tracking"We can identify problems from the final answer."Record every state throughout the run.It becomes difficult to determine where the problem occurred.

Exercises

Each exercise ends with a value on the last line. Press Check to compare it with the expected answer.

What to Remember

  • An agent is always in one state at a time: Idle, Reasoning, Action, Waiting, Completion, or Failed.
  • Transition rules define which state changes are allowed. Writing these rules as a table makes agent behavior easier to understand and validate.
  • Every agent run should be checked against the transition rules. If the agent makes an invalid state transition, it indicates a bug in the system.
  • A Failed state can sometimes recover by returning to Reasoning, but recovery attempts should always be limited.
  • Only the Completion state means the goal was successfully achieved. Any other final state should be treated as a failed run.

Next: Agent Configuration, how to give an agent a role, rules and limits.