Skip to main content
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.

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:
  1. The agent stops executing and emits an interrupt payload
  2. The useStream hook surfaces the interrupt via stream.interrupt
  3. Your UI renders a review card with approve/reject/edit options
  4. The user makes a decision
  5. Your code calls stream.submit() with a resume command
  6. 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 to useStream 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:

Decision types

The HITL pattern supports three 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:

Building the ApprovalCard

Here is a full approval card component that handles all three decision types:

The resume flow

After the user makes a decision, the full cycle looks like this:
  1. Call stream.submit(null, { command: { resume: hitlResponse } })
  2. The useStream hook sends the resume command to the LangGraph backend
  3. The agent receives the HITLResponse and continues execution
  4. If approved, the tool runs with the original (or edited) arguments
  5. If rejected, the agent receives the reason and decides its next step
  6. The interrupt property resets to null as the agent resumes streaming
You can chain multiple HITL checkpoints in a single agent run. For example, an agent might ask for approval to search, then ask again before sending an email with the results. Each interrupt is handled independently.

Common use cases

Handling multiple pending actions

An interrupt can contain multiple actionRequests 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. useStream handles 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.