# State Machines

Learn how to guide users through multi-step conversations using a state machine pattern.

## [Overview](https://docs.copilotkit.ai/cookbook/state-machine\#overview)

When building chat-based applications, you often need to guide users through a series of steps or **stages**. This recipe shows how to implement a state machine pattern to keep your assistant focused and on-track.

- Live Example: [https://state-machine-copilot.vercel.app/](https://state-machine-copilot.vercel.app/)
- Example Source Code: [https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine)

This recipe assumes you have completed the [quickstart guide](https://docs.copilotkit.ai/quickstart) and have a basic CopilotKit application running.

### [What is a State Machine?](https://docs.copilotkit.ai/cookbook/state-machine\#what-is-a-state-machine)

A state machine is a model where your application can be in exactly one state at a time, with clear rules about how to move between states. For chat applications, this means:

- The assistant knows exactly what stage of the conversation it's in
- Only certain actions are available in each stage
- There are clear rules for moving to the next stage

### [State Machines in CopilotKit](https://docs.copilotkit.ai/cookbook/state-machine\#state-machines-in-copilotkit)

When implementing a state machine in CopilotKit, the main piece that enables this pattern is the `available` prop present in
most of our hooks. This prop will allow you conditionally control what instructions, context, and actions are available to
the assistant.

In this recipe, we combine the `available` prop with React state to control when each stage is active, sometimes through
standard deterministic update (button clicks), and sometimes through LLM-driven actions.

![State Machine Architecture](https://docs.copilotkit.ai/_next/image?url=%2Fimages%2Fstate-machine-arch.png&w=3840&q=75)

## [Basic Implementation](https://docs.copilotkit.ai/cookbook/state-machine\#basic-implementation)

### [Create a stage](https://docs.copilotkit.ai/cookbook/state-machine\#create-a-stage)

Each stage is composed of stage-specific instructions, context, and actions. These are enabled or disabled
as the stage changes via the `available` prop. In this example of a stage, we are extracting a user's name
and ensuring it is not in a list of other names.

```
import {
  useCopilotAdditionalInstructions,
  useCopilotAction,
  useCopilotReadable
} from "@copilotkit/react-core";

// ...

/*
 * Not required, but it is convenient to use a dedicated hook to define each
 * stage of the state machine
 */
function useStageOne(
  stage: string,
  setStage: (stage: string) => void,
  setName: (name: string) => void
) {

  /*
   * Each stage can define its own instructions, context, and transitions
   * (implemented via copilotActions). We transition between stages by simply
   * setting the `stage` variable from the handler of the transition:
   */

  // Add additional instructions to the system prompt if this stage is active
  useCopilotAdditionalInstructions({
    instructions: "Ask for the user's name politely.",
    // Use "available" argument to enable this only when the stage is correct!
    available: stage === "one" ? "available" : "disabled"
  })

  // Add context to the system prompt if this stage is active
  useCopilotReadable({
    description: "Other names",
    value: ["John", "Jane", "Jim"],
    available: stage === "one" ? "available" : "disabled"
  })

  // Add an action to the assistant that transitions to the next stage if this stage is active
  useCopilotAction({
    name: "transitionToNextStage",
    description: "Moves to the next stage, only call is the user's name is not in the list of other names",
    available: stage === "one" ? "available" : "disabled",
    parameters: [\
      { name: "name", type: "string", description: "The name of the user", required: true },\
    ],
    handler: ({ name }) => {
      // Perform any state updates given the user's input
      setName(name);

      // Transition to the next stage
      setStage("two");
    }
  });
}
```

### [Create another stage](https://docs.copilotkit.ai/cookbook/state-machine\#create-another-stage)

Now, let's create a second stage that's simple and just greets the user by name as a pirate. This is mainly just to
demonstrate how to add any additional stages. The name will be made available to this stage in the next step.

```
import { useCopilotAdditionalInstructions } from "@copilotkit/react-core";

// ...

function useStageTwo(stage: string) => void) {
  // Add stage-specific instructions - only available in stage "two"
  useCopilotAdditionalInstructions({
    instructions: "Talk to the user about their name and refer to them like a pirate would.",
    available: stage === "two" ? "available" : "disabled"
  })

  // ...
}

// Any additional stages you want to add...
```

### [Put it all together](https://docs.copilotkit.ai/cookbook/state-machine\#put-it-all-together)

Finally, bring everything together into a chat component:

```
import { useState } from "react";
import { CopilotKit, useCopilotReadable } from "@copilotkit/react-core";
import { CopilotChat } from "@copilotkit/react-ui";

// ...

function StateMachineChat() {
  // Track the current stage and user's name
  const [stage, setStage] = useState<string>("one");
  const [name, setName] = useState<string>("");

  // Readable context available across all stages
  useCopilotReadable({
    description: "User's name",
    value: name,
  }, [name])

  // Initialize all stages with their required props
  useStageOne(stage, setStage, setName);
  useStageTwo(stage);
  // any additional stages...

  return (
    <CopilotKit>
      <CopilotChat/>
    </CopilotKit>
  )
}
```

### Full example code

### [🎉 You've implemented a state machine!](https://docs.copilotkit.ai/cookbook/state-machine\#-youve-implemented-a-state-machine)

To recap, each stage hook uses the `available` prop to control when its instructions, context, and actions are accessible to the assistant. This ensures that the assistant only uses the correct tools and context for the current stage.

Next, let's see some advanced patterns you can implement with these fundamentals.

## [Advanced Patterns](https://docs.copilotkit.ai/cookbook/state-machine\#advanced-patterns)

This state machine pattern can be extended for complex interactions. Below are some advanced patterns you can implement with code sourced in our
[car sales example](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine) which you already saw a demo of in the [overview](https://docs.copilotkit.ai/cookbook/state-machine#overview).

### [Stage Transition Approaches](https://docs.copilotkit.ai/cookbook/state-machine\#stage-transition-approaches)

#### [Code-driven Stage Transitions](https://docs.copilotkit.ai/cookbook/state-machine\#code-driven-stage-transitions)

When you want to transition between stages, you can do so by setting the `stage` deterministically, at any point in code.

```
const [stage, setStage] = useState<string>("one");

// ...

<button onClick={() => setStage("two")}>
  Transition to next stage
</button>
```

The car sales demo uses this approach in generative UI (for more on generative UI, see the [section below](https://docs.copilotkit.ai/cookbook/state-machine#generative-ui)) to transition between stages
when a user submits their contact information.

Click here for the [source code](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine/src/lib/stages/use-stage-get-contact-info.tsx)

src/lib/stages/use-stage-get-contact-info.tsx

```
// imports ...

export function useStageGetContactInfo() {
  const { setContactInfo, stage, setStage } = useGlobalState();

  // ...

  // Render the ContactInfo component and wait for the user's response.
  useCopilotAction(
    {
      name: "getContactInformation",
      description: "Get the contact information of the user",
      available: stage === "getContactInfo" ? "enabled" : "disabled",
      renderAndWaitForResponse: ({ status, respond }) => {
        return (
          <ContactInfo
            status={status}

            onSubmit={(name, email, phone) => {
              // Commit the contact information to the global state.
              setContactInfo({ name, email, phone });

              // Let the agent know that the user has submitted their contact information.
              respond?.("User has submitted their contact information.");

              // This move the state machine to the next stage, buildCar deterministically.
              setStage("buildCar");
            }}
          />
        );
      },
    },
    [stage],
  );
}
```

#### [LLM-Driven Stage Transitions](https://docs.copilotkit.ai/cookbook/state-machine\#llm-driven-stage-transitions)

Sometimes you need stages that can transition to different next stages based on user input or LLM-driven actions.

Click here for the [source code](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine/src/lib/stages/use-stage-sell-financing.tsx)

src/lib/stages/use-stage-sell-financing.tsx

```
function useStageSellFinancing() {
  const { stage, setStage } = useGlobalState();
  const isActive = stage === "sellFinancing";

  // Provide context to the AI
  useCopilotReadable({
    description: "Financing Information",
    value: "Current promotion: 0% financing for 60 months...",
    available: isActive ? "enabled" : "disabled"
  });

  // Different paths based on financing choice by user, LLM will decide which path to take

  useCopilotAction({
    name: "selectFinancing",
    description: "Select the financing option",
    available: stage === "sellFinancing" ? "enabled" : "disabled",
    handler: () => setStage("getFinancingInfo"),
  }, [stage]);

  useCopilotAction({
    name: "selectNoFinancing",
    description: "Select the no financing option",
    available: stage === "sellFinancing" ? "enabled" : "disabled",
    handler: () => setStage("getPaymentInfo"),
  }, [stage]);

}
```

### [Generative UI](https://docs.copilotkit.ai/cookbook/state-machine\#generative-ui)

[Generative UI](https://docs.copilotkit.ai/guides/generative-ui) is a pattern where tool calls are streamed and rendered for the user to visualize the progress an agent is making. It can also be combined with the **Human-in-the-loop pattern** to allow checkpoints where the user can intervene and help guide the agent.

When combined with the state machine pattern, you can build deep and interactive conversations with the user. For example, the `buildCar` stage in the car sales demo
uses generative UI to show the user available cars that they can choose from.

Click here for the [source code](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine/src/lib/stages/use-stage-build-car.tsx)

Build Car StageShow Car Component

src/lib/stages/use-stage-build-car.tsx

```
export function useStageBuildCar() {
  const { setSelectedCar, stage, setStage } = useGlobalState();

  // ...

  useCopilotAction({
    name: "showCar",
    description: "Show a single car that you have in mind. Do not call this more than once, call `showMultipleCars` if you have multiple cars to show.",
    available: stage === "buildCar" ? "enabled" : "disabled",
    parameters: [\
      // excluded for brevity, see source code link above for more detail\
    ],
    renderAndWaitForResponse: ({ args, status, respond }) => {
      const { car } = args;
      return (

        <ShowCar
          car={(car as Car) || ({} as Car)}
          status={status}
          onSelect={() => {
            setSelectedCar((car as Car) || ({} as Car));
            respond?.("User has selected a car you can see it in your readables, the system will now move to the next state, do not call call nextState.");
            setStage("sellFinancing");
          }}
          onReject={() => respond?.("User wants to select a different car, please stay in this state and help them select a different car")}
        />
      );
    },
  }, [stage]);
  // ...
}
```

### [Initial message loading](https://docs.copilotkit.ai/cookbook/state-machine\#initial-message-loading)

To add an initial message to the chat, we can use the `appendMessage` function provided by the `useCopilotChat` hook.

Improved experience coming soon

This is a temporary solution and we will be improving this in the near future.

Click here for the [source code](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine/src/components/car-sales-chat.tsx)

src/components/car-sales-chat.tsx

```
import { useCopilotChat } from "@copilotkit/react-core";

// ...

const { appendMessage, isLoading } = useCopilotChat();

// Render an initial message when the chat is first loaded
useEffect(() => {
  if (initialMessageSent || isLoading) return;

  setTimeout(() => {
    appendMessage(
      new TextMessage({
        content:
          "Hi, I'm Fio, your AI car salesman. First, let's get your contact information before we get started.",
        role: MessageRole.Assistant,
      }),
    );
    setInitialMessageSent(true);
  }, 500);
}, [initialMessageSent, appendMessage, isLoading]);

// ...
```

### [Tools When Entering a Stage](https://docs.copilotkit.ai/cookbook/state-machine\#tools-when-entering-a-stage)

Sometimes you'll want to guide the AI to call a specific tool when entering a stage.

The payment info stage demonstrates how to guide the AI to make specific tool calls by
adding additional instructions to call the `getPaymentInformation` tool explicitly.

Click here for the [source code](https://github.com/CopilotKit/CopilotKit/tree/main/examples/copilot-state-machine/src/lib/stages/use-stage-get-payment-info.tsx)

src/lib/stages/use-stage-get-payment-info.tsx

```
export function useStageGetPaymentInfo() {
  const { setCardInfo, stage, setStage } = useGlobalState();

  // Conditionally add additional instructions for the agent's prompt.
  useCopilotAdditionalInstructions({
    available: stage === "getPaymentInfo" ? "enabled" : "disabled",

    instructions: `
        CURRENT STATE: You are now getting the payment information of the user.
        Say, 'Great! Now I need to get your payment information.' and MAKE SURE
        to then call the 'getPaymentInformation' action.
    `,
  }, [stage]);

  // ...

}
```

## [Recap](https://docs.copilotkit.ai/cookbook/state-machine\#recap)

This recipe introduced a powerful pattern for building conversational AI applications using state machines. By breaking down complex interactions into discrete stages, each with
focused instructions and actions, we can create more maintainable and user-friendly experiences.

With this pattern, you can start building your own multi-stage conversations.

## [Need Help?](https://docs.copilotkit.ai/cookbook/state-machine\#need-help)

Need help or want to share what you've built? Join our [Discord community](https://discord.gg/6dffbvGU3D) or open an issue on [GitHub](https://github.com/CopilotKit/CopilotKit/issues/new/choose).

[Previous\\
\\
Next Steps](https://docs.copilotkit.ai/tutorials/ai-powered-textarea/next-steps) [Next\\
\\
Common Issues](https://docs.copilotkit.ai/troubleshooting/common-issues)

### On this page

[Overview](https://docs.copilotkit.ai/cookbook/state-machine#overview) [What is a State Machine?](https://docs.copilotkit.ai/cookbook/state-machine#what-is-a-state-machine) [State Machines in CopilotKit](https://docs.copilotkit.ai/cookbook/state-machine#state-machines-in-copilotkit) [Basic Implementation](https://docs.copilotkit.ai/cookbook/state-machine#basic-implementation) [Create a stage](https://docs.copilotkit.ai/cookbook/state-machine#create-a-stage) [Create another stage](https://docs.copilotkit.ai/cookbook/state-machine#create-another-stage) [Put it all together](https://docs.copilotkit.ai/cookbook/state-machine#put-it-all-together) [🎉 You've implemented a state machine!](https://docs.copilotkit.ai/cookbook/state-machine#-youve-implemented-a-state-machine) [Advanced Patterns](https://docs.copilotkit.ai/cookbook/state-machine#advanced-patterns) [Stage Transition Approaches](https://docs.copilotkit.ai/cookbook/state-machine#stage-transition-approaches) [Code-driven Stage Transitions](https://docs.copilotkit.ai/cookbook/state-machine#code-driven-stage-transitions) [LLM-Driven Stage Transitions](https://docs.copilotkit.ai/cookbook/state-machine#llm-driven-stage-transitions) [Generative UI](https://docs.copilotkit.ai/cookbook/state-machine#generative-ui) [Initial message loading](https://docs.copilotkit.ai/cookbook/state-machine#initial-message-loading) [Tools When Entering a Stage](https://docs.copilotkit.ai/cookbook/state-machine#tools-when-entering-a-stage) [Recap](https://docs.copilotkit.ai/cookbook/state-machine#recap) [Need Help?](https://docs.copilotkit.ai/cookbook/state-machine#need-help)

[Edit on GitHub](https://github.com/CopilotKit/CopilotKit/blob/main/docs/content/docs/(root)/cookbook/state-machine.mdx)

![](https://static.scarf.sh/a.png?x-pxid=ffc9f65d-0186-4575-b065-61d62ea9d7d3)

![State Machine Architecture](https://docs.copilotkit.ai/_next/image?url=%2Fimages%2Fstate-machine-arch.png&w=3840&q=75)

## Agent State Management
CrewAI CrewAI support is here! Checkout the [Crew](https://docs.copilotkit.ai/crewai-crews) and [Flow](https://docs.copilotkit.ai/crewai-flows) documentation.

Search docs

`⌘`  `K`

On this pageUsage