---
title: Tool-based
description: Implement HITL with Mastra using frontend tools that render UI and collect user input.
icon: lucide/Share2
---
<IframeSwitcher
  id="human-in-the-loop-tool-based-example"
  exampleUrl="https://feature-viewer.copilotkit.ai/mastra/feature/human_in_the_loop?sidebar=false&chatDefaultOpen=false"
  codeUrl="https://feature-viewer.copilotkit.ai/mastra/feature/human_in_the_loop?view=code&sidebar=false&codeLayout=tabs"
  exampleLabel="Demo"
  codeLabel="Code"
  height="700px"
/>

## What is this?

CopilotKit lets you add custom UI to take user input and then pass it back to the agent upon completion.
This approach uses `useHumanInTheLoop` to register a frontend tool that renders a UI component and waits for the user's response.

<Callout type="info">
  Looking for an approach where tools can pause mid-execution and wait for user input? See the [interrupt-based approach](/mastra/human-in-the-loop/interrupt-flow).
</Callout>

## Why should I use this?

Human-in-the-loop is a powerful way to implement complex workflows that are production ready. By having a human in the loop,
you can ensure that the agent is always making the right decisions and ultimately is being steered in the right direction.

## Implementation

<Steps>
  <Step>
    ### Run and connect your agent
    <RunAndConnect />
  </Step>

  <Step>
    ### Add a human-in-the-loop tool to your Frontend
    First, we'll create a component that offers the user options and waits for their selection.

    ```tsx title="ui/app/page.tsx"
    import { useHumanInTheLoop } from "@copilotkit/react-core/v2" // [!code highlight]

    function YourMainContent() {
      // ...

      useHumanInTheLoop({
        name: "offerOptions",
        description: "Give the user a choice between two options and have them select one.",
        parameters: [
          {
            name: "option_1",
            type: "string",
            description: "The first option",
            required: true,
          },
          {
            name: "option_2",
            type: "string",
            description: "The second option",
            required: true,
          },
        ],
        render: ({ args, respond }) => {
          if (!respond) return <></>;
          return (
            <div>
              {/* [!code highlight:2] */}
              <button onClick={() => respond(`${args.option_1} was selected`)}>{args.option_1}</button>
              <button onClick={() => respond(`${args.option_2} was selected`)}>{args.option_2}</button>
            </div>
          );
        },
      });

      // ...
    }
    ```
  </Step>

  <Step>
    ### Setup the Mastra Agent
    On the agent side, we are already done! Mastra natively supports the AG-UI protocol and will automatically
    pass control back to the frontend when the `offerOptions` tool is called by the agent.
  </Step>
  <Step>
    ### Give it a try!
    Try asking your agent something that requires a choice.

    ```
    Can you show me two good options for a restaurant name?"
    ```

    You'll see that the agent will present two options and wait for you to select one before continuing.
  </Step>
</Steps>
