--- title: "useHumanInTheLoop" description: "React hook for interactive tools that pause agent execution and wait for user input" --- ## Overview `useHumanInTheLoop` registers an interactive tool that pauses agent execution until the user responds through your custom UI. Unlike `useFrontendTool`, there is no `handler` function. Instead, the hook provides an internal status machine (`InProgress` -> `Executing` -> `Complete`) and supplies a `respond` callback to the render component while the tool is in the `Executing` state. The agent remains paused until `respond` is called with the user's input. Re-exported from `@copilotkit/react-core/v2`, identical to the [React (V2) `useHumanInTheLoop`](/reference/v2/hooks/useHumanInTheLoop). The only difference is the import path. This hook is built on top of `useFrontendTool` with an internally managed handler that resolves the tool call promise when `respond` is invoked. Use it for confirmation dialogs, approval workflows, form collection, or any scenario where a human must provide input before the agent can continue. The `render` component returns React Native elements that CopilotKit surfaces in the chat. See [`useRenderTool`](/reference/react-native/hooks/useRenderTool) for the underlying React Native render mechanism. ## Signature ```tsx import { useHumanInTheLoop } from "@copilotkit/react-native"; function useHumanInTheLoop>( tool: ReactHumanInTheLoop, deps?: ReadonlyArray, ): void; ``` ## Parameters The interactive tool definition. A unique name for the tool. The agent references this name when it needs human input. A natural-language description that tells the agent what the tool does and when to invoke it (e.g., "Ask the user to confirm before deleting records"). A Zod schema defining the arguments the agent passes to the tool. These arguments are forwarded to the render component so you can build context-aware UI. A React Native component that drives the human interaction. The component receives different props depending on the current status: **When `status` is `ToolCallStatus.InProgress`:** - `args: Partial`: partially streamed arguments - `respond: undefined`: not yet available - `result: undefined` **When `status` is `ToolCallStatus.Executing`:** - `args: T`: fully resolved arguments - `respond: (result: unknown) => Promise`: call this to send the user's response back to the agent and resume execution - `result: undefined` **When `status` is `ToolCallStatus.Complete`:** - `args: T`: the original arguments - `respond: undefined`: no longer available - `result: string`: the serialized result Controls tool availability. Set to `"disabled"` to temporarily prevent the agent from requesting human input through this tool. An optional dependency array. When provided, the tool registration is refreshed whenever any value in the array changes. ## Usage ### Confirmation Dialog A common pattern where the agent asks the user to confirm a destructive action. ```tsx import { Text, TouchableOpacity, View } from "react-native"; import { useHumanInTheLoop, ToolCallStatus } from "@copilotkit/react-native"; import { z } from "zod"; function DeleteConfirmation() { useHumanInTheLoop( { name: "confirmDeletion", description: "Ask the user to confirm before deleting items", parameters: z.object({ itemName: z.string().describe("Name of the item to delete"), itemCount: z.number().describe("Number of items to delete"), }), render: ({ args, status, respond, result }) => { if (status === ToolCallStatus.InProgress) { return ( Preparing confirmation... ); } if (status === ToolCallStatus.Executing && respond) { return ( Are you sure you want to delete {args.itemCount} {args.itemName} (s)? respond({ confirmed: true })} style={{ backgroundColor: "#ef4444", paddingHorizontal: 16, paddingVertical: 8, borderRadius: 6 }} > Delete respond({ confirmed: false })} style={{ backgroundColor: "#d1d5db", paddingHorizontal: 16, paddingVertical: 8, borderRadius: 6 }} > Cancel ); } if (status === ToolCallStatus.Complete && result) { const parsed = JSON.parse(result); return ( {parsed.confirmed ? "Items deleted." : "Deletion cancelled."} ); } return null; }, }, [], ); return null; } ``` ### Form Input Collection Collect structured input from the user before the agent proceeds. ```tsx import { useState } from "react"; import { Text, TextInput, TouchableOpacity, View } from "react-native"; import { useHumanInTheLoop, ToolCallStatus } from "@copilotkit/react-native"; import { z } from "zod"; function ShippingAddressForm() { useHumanInTheLoop( { name: "collectShippingAddress", description: "Collect shipping address from the user before placing an order", parameters: z.object({ orderSummary: z .string() .describe("A summary of the order being placed"), }), render: ({ args, status, respond }) => { const [address, setAddress] = useState({ street: "", city: "", zip: "", }); if (status === ToolCallStatus.Executing && respond) { return ( Order: {args.orderSummary} Please enter your shipping address: setAddress({ ...address, street })} style={{ borderWidth: 1, padding: 8, borderRadius: 6 }} /> setAddress({ ...address, city })} style={{ borderWidth: 1, padding: 8, borderRadius: 6 }} /> setAddress({ ...address, zip })} style={{ borderWidth: 1, padding: 8, borderRadius: 6 }} /> respond(address)} style={{ backgroundColor: "#3b82f6", paddingHorizontal: 16, paddingVertical: 8, borderRadius: 6 }} > Submit Address ); } if (status === ToolCallStatus.Complete) { return ( Shipping address submitted. ); } return null; }, }, [], ); return null; } ``` ### Approval Workflow with Context ```tsx import { Text, TouchableOpacity, View } from "react-native"; import { useHumanInTheLoop, ToolCallStatus } from "@copilotkit/react-native"; import { z } from "zod"; function ExpenseApproval() { useHumanInTheLoop( { name: "approveExpense", description: "Request manager approval for an expense report", parameters: z.object({ employeeName: z.string().describe("Name of the employee"), amount: z.number().describe("Expense amount in dollars"), category: z.string().describe("Expense category"), description: z.string().describe("Description of the expense"), }), render: ({ args, status, respond, result }) => { if (status === ToolCallStatus.Executing && respond) { return ( Expense Approval Required Employee: {args.employeeName} Amount: ${args.amount.toFixed(2)} Category: {args.category} Description: {args.description} respond({ approved: true })} style={{ backgroundColor: "#22c55e", paddingHorizontal: 16, paddingVertical: 8, borderRadius: 6 }} > Approve respond({ approved: false, reason: "Needs more detail" }) } style={{ backgroundColor: "#ef4444", paddingHorizontal: 16, paddingVertical: 8, borderRadius: 6 }} > Reject ); } if (status === ToolCallStatus.Complete && result) { const parsed = JSON.parse(result); return ( {parsed.approved ? "Expense approved." : `Expense rejected: ${parsed.reason}`} ); } return null; }, }, [], ); return null; } ``` ## Behavior - **Blocks agent execution**: The agent pauses when this tool is called and waits for the `respond` callback to be invoked before continuing. - **Internal status machine**: The hook manages three states: `InProgress` (arguments streaming in), `Executing` (waiting for user response), and `Complete` (user has responded). Your render component receives the appropriate props for each state. - **Single response**: The `respond` callback should only be called once per tool invocation. Calling it resolves the tool call promise with the provided value. - **Built on `useFrontendTool`**: Under the hood, this hook wraps `useFrontendTool` with an internally generated handler, so all the same lifecycle behavior (mount/unmount registration, duplicate warnings) applies. - **Mount/Unmount lifecycle**: The tool and its render component are registered on mount and removed on unmount. - **No return value**: The hook returns `void`. ## Related - [`useFrontendTool`](/reference/react-native/hooks/useFrontendTool): for tools with automated handlers that do not require user interaction - [`useRenderTool`](/reference/react-native/hooks/useRenderTool): the React Native mechanism for rendering tool calls inline in chat - [`ToolCallStatus`](#toolcallstatus): the status enum used across tool hooks - [React (V2) reference](/reference/v2/hooks/useHumanInTheLoop) ## ToolCallStatus The `ToolCallStatus` enum is exported from `@copilotkit/react-native` and defines the three phases of tool execution: | Value | Description | | --------------------------- | ------------------------------------------------------------------------------------------- | | `ToolCallStatus.InProgress` | Arguments are being streamed from the agent. The tool has not started executing yet. | | `ToolCallStatus.Executing` | Arguments are fully resolved. For `useHumanInTheLoop`, the `respond` callback is available. | | `ToolCallStatus.Complete` | Execution is finished. The `result` string is available. |