Not every agent action should run unsupervised. When an agent is about to send an email, delete a record, execute a financial transaction, or perform any irreversible operation, you need a human to review and approve the action first. The Human-in-the-Loop (HITL) pattern lets your agent pause execution, present the pending action to the user, and resume only after explicit approval.Documentation Index
Fetch the complete documentation index at: https://langchain-5e9cc07a-preview-mdrxyo-1777658790-7be347c.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
How interrupts work
LangGraph agents support interrupts, explicit pause points where the agent yields control back to the client. When the agent hits an interrupt:- The agent stops executing and emits an interrupt payload
- The
useStreamhook surfaces the interrupt viastream.interrupt - Your UI renders a review card with approve/reject/edit options
- The user makes a decision
- Your code calls
stream.submit()with a resume command - The agent picks up where it left off
Setting up useStream for HITL
Define a TypeScript interface matching your agent’s state schema and pass it as a type parameter touseStream for type-safe access to state values. In the examples below, replace typeof myAgent with your interface name:
The interrupt payload
When the agent pauses,stream.interrupt contains a HITLRequest with the
following structure:
| Property | Description |
|---|---|
actionRequests | Array of pending actions the agent wants to perform |
actionRequests[].action | The action name (e.g. "send_email", "delete_record") |
actionRequests[].args | Structured arguments for the action |
actionRequests[].description | Optional human-readable description of what the action does |
reviewConfigs | Per-action configuration controlling which decisions are allowed |
reviewConfigs[].allowedDecisions | Which buttons to show: "approve", "reject", "edit", "respond" |
Decision types
The HITL pattern supports four decision types:Approve
The user confirms the action should proceed as-is:Reject
The user denies the action with an optional reason:When an action is rejected, the agent receives the rejection reason and can
decide how to proceed. It may rephrase, ask clarifying questions, or abandon
the action entirely.
Edit
The user modifies the action’s arguments before approving:Respond
The user provides a direct reply for “ask user” style tools. Themessage becomes the tool result and the tool itself is not executed:
Use
respond when the tool is intentionally a placeholder for human input — for example, an ask_user tool that prompts the agent to collect information from the user.Building the ApprovalCard
Here is a full approval card component that handles all four decision types:The resume flow
After the user makes a decision, the full cycle looks like this:- Call
stream.submit(null, { command: { resume: hitlResponse } }) - The
useStreamhook sends the resume command to the LangGraph backend - The agent receives the
HITLResponseand continues execution. The HITL response may be one of:"approve": The agent continues executing the next action"reject": The agent receives the rejection reasoning and decides its next step"edit": The agent runs the tool with the edited arguments"respond": The human’s message is returned directly as the tool result without executing the tool
- The
interruptproperty resets tonullas the agent resumes streaming
Common use cases
| Use Case | Action | Review Config |
|---|---|---|
| Email sending | send_email | ["approve", "reject", "edit"] |
| Database writes | update_record | ["approve", "reject"] |
| Financial transactions | transfer_funds | ["approve", "reject"] |
| File deletion | delete_files | ["approve", "reject"] |
| API calls to external services | call_api | ["approve", "reject", "edit"] |
| Collecting user input | ask_user | ["respond"] |
Handling multiple pending actions
An interrupt can contain multipleactionRequests when the agent wants to
perform several actions at once. Render a card for each and collect all
decisions before resuming:
Best practices
Keep these guidelines in mind when implementing HITL workflows:- Show clear context. Always display what the agent wants to do and why. Include the action description and the full arguments.
- Make approve the easiest path. If the action looks correct, approving should be a single click. Reserve multi-step flows for reject/edit.
- Validate edited args. When users edit action arguments, validate the JSON structure before sending. Show inline errors for malformed input.
- Persist the interrupt state. If the user refreshes the page, the
interrupt should still be visible.
useStreamhandles this via the thread’s checkpoint. - Log all decisions. For audit trails, log every approve/reject/edit decision with timestamps and the user who made the decision.
- Set timeouts thoughtfully. Long-running agents should not block indefinitely on human review. Consider showing how long the agent has been waiting.
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

