approve), modified before running (edit), or rejected with feedback (reject).
Interrupt decision types
The middleware defines three built-in ways a human can respond to an interrupt:
The available decision types for each tool depend on the policy you configure in
interrupt_on.
When multiple tool calls are paused at the same time, each action requires a separate decision.
Decisions must be provided in the same order as the actions appear in the interrupt request.
Configuring interrupts
To use HITL, add the middleware to the agent’smiddleware list when creating the agent.
You configure it with a mapping of tool actions to the decision types that are allowed for each action. The middleware will interrupt execution when a tool call matches an action in the mapping.
You must configure a checkpointer to persist the graph state across interrupts.
In production, use a persistent checkpointer like
AsyncPostgresSaver. For testing or prototyping, use InMemorySaver.When invoking the agent, pass a config that includes the thread ID to associate execution with a conversation thread.
See the LangGraph interrupts documentation for details.Configuration options
Configuration options
dict
required
Mapping of tool names to approval configs. Values can be
True (interrupt with default config), False (auto-approve), or an InterruptOnConfig object.string
default:"Tool execution requires approval"
Prefix for action request descriptions
InterruptOnConfig options:list[string]
List of allowed decisions:
'approve', 'edit', or 'reject'string | callable
Static string or callable function for custom description
Responding to interrupts
When you invoke the agent, it runs until it either completes or an interrupt is raised. An interrupt is triggered when a tool call matches the policy you configured ininterrupt_on. In that case, the invocation result will include an __interrupt__ field with the actions that require review. You can then present those actions to a reviewer and resume execution once decisions are provided.
Decision types
- ✅ approve
- ✏️ edit
- ❌ reject
Use
approve to approve the tool call as-is and execute it without changes.Streaming with human-in-the-loop
You can usestream() instead of invoke() to get real-time updates while the agent runs and handles interrupts. Use stream_mode=['updates', 'messages'] to stream both agent progress and LLM tokens.
Execution lifecycle
The middleware defines anafter_model hook that runs after the model generates a response but before any tool calls are executed:
- The agent invokes the model to generate a response.
- The middleware inspects the response for tool calls.
- If any calls require human input, the middleware builds a
HITLRequestwithaction_requestsandreview_configsand calls interrupt. - The agent waits for human decisions.
- Based on the
HITLResponsedecisions, the middleware executes approved or edited calls, synthesizes ToolMessage’s for rejected calls, and resumes execution.
Custom HITL logic
For more specialized workflows, you can build custom HITL logic directly using the interrupt primitive and middleware abstraction. Review the execution lifecycle above to understand how to integrate interrupts into the agent’s operation.Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

