원클릭으로
deepagents-hitl
Implementing human-in-the-loop approval workflows with interrupt_on parameter for sensitive tool operations in Deep Agents.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Implementing human-in-the-loop approval workflows with interrupt_on parameter for sensitive tool operations in Deep Agents.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Using the Deep Agents CLI - terminal interface, persistent memory with AGENTS.md, project conventions, skills directories, and CLI commands.
Understanding Deep Agents framework - what they are, how to create them with createDeepAgent, and the agent harness architecture with built-in middleware for planning, filesystems, and subagents.
Creating and using custom skills with progressive disclosure, SKILL.md format, and the Agent Skills protocol in Deep Agents.
Using the Deep Agents CLI - terminal interface, persistent memory with AGENTS.md, project conventions, skills directories, and CLI commands.
Using FilesystemMiddleware with virtual filesystems, backends (State, Store, Filesystem, Composite), and context management for Deep Agents.
Using FilesystemMiddleware with virtual filesystems, backends (State, Store, Filesystem, Composite), and context management for Deep Agents.
| name | deepagents-hitl |
| description | Implementing human-in-the-loop approval workflows with interrupt_on parameter for sensitive tool operations in Deep Agents. |
| language | python |
Human-in-the-Loop (HITL) middleware adds human oversight to tool calls. When the agent proposes a sensitive action, execution pauses for human decision:
Requires LangGraph's persistence (checkpointer) to save state during interrupts.
| Use HITL When | Skip HITL When |
|---|---|
| High-stakes operations (DB writes, deployments) | Read-only operations |
| Compliance requires human oversight | Fully automated workflows |
| Expensive API calls need verification | Low-cost operations |
| Learning agent behavior | Trusted, tested operations |
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
interrupt_on={
"write_file": True, # All decisions allowed (approve/edit/reject)
"execute_sql": {"allowed_decisions": ["approve", "reject"]}, # No editing
"read_file": False, # No interrupts
},
checkpointer=MemorySaver() # REQUIRED for interrupts
)
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import MemorySaver
agent = create_agent(
model="gpt-4",
tools=[write_file_tool, execute_sql_tool, read_data_tool],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"write_file": True,
"execute_sql": {"allowed_decisions": ["approve", "reject"]},
"read_data": False,
},
description_prefix="Tool execution pending approval",
),
],
checkpointer=MemorySaver(),
)
| Tool Type | Interrupt Config | Allowed Decisions | Use Case |
|---|---|---|---|
| Destructive | True | approve, edit, reject | write_file, delete_record |
| Critical | {"allowed_decisions": ["approve", "reject"]} | approve, reject only | deploy_code, execute_sql |
| Safe | False | none | read_file, get_weather |
| Expensive | True | approve, edit, reject | call_paid_api |
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
interrupt_on={"write_file": True},
checkpointer=MemorySaver()
)
# Initial invocation
config = {"configurable": {"thread_id": "session-1"}}
result = agent.invoke({
"messages": [{"role": "user", "content": "Write deployment config to /config/prod.yaml"}]
}, config=config)
# Execution pauses - check for interrupts
state = agent.get_state(config)
if state.next: # Has interrupts
for interrupt in state.tasks:
print(f"Interrupt: {interrupt}")
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
from langchain.schema import Command
agent = create_deep_agent(
interrupt_on={"write_file": True},
checkpointer=MemorySaver()
)
config = {"configurable": {"thread_id": "session-1"}}
# Step 1: Agent proposes write_file
result = agent.invoke({
"messages": [{"role": "user", "content": "Write config to /prod.yaml"}]
}, config=config)
# Step 2: Get interrupts
state = agent.get_state(config)
interrupt = state.tasks[0] # First interrupt
# Step 3: Approve
agent.update_state(
config,
{
"messages": [
Command(
resume={
"decisions": [{"type": "approve"}]
}
)
]
}
)
# Step 4: Continue execution
result = agent.invoke(None, config=config)
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
from langchain.schema import Command
agent = create_deep_agent(
interrupt_on={"execute_sql": True},
checkpointer=MemorySaver()
)
config = {"configurable": {"thread_id": "session-1"}}
# Agent proposes SQL
result = agent.invoke({
"messages": [{"role": "user", "content": "Delete old records from users table"}]
}, config=config)
# Get interrupt details
state = agent.get_state(config)
interrupt = state.tasks[0]
print(f"Proposed SQL: {interrupt.value['action_requests'][0]['args']}")
# Edit the SQL query
agent.update_state(
config,
{
"messages": [
Command(
resume={
"decisions": [{
"type": "edit",
"args": {
"query": "DELETE FROM users WHERE last_login < '2020-01-01' LIMIT 100"
}
}]
}
)
]
}
)
# Continue with edited query
result = agent.invoke(None, config=config)
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
from langchain.schema import Command
agent = create_deep_agent(
interrupt_on={"deploy_code": True},
checkpointer=MemorySaver()
)
config = {"configurable": {"thread_id": "session-1"}}
result = agent.invoke({
"messages": [{"role": "user", "content": "Deploy to production"}]
}, config=config)
# Reject deployment
agent.update_state(
config,
{
"messages": [
Command(
resume={
"decisions": [{
"type": "reject",
"message": "Tests haven't passed yet. Run tests first."
}]
}
)
]
}
)
# Agent receives rejection feedback and can try alternative approach
result = agent.invoke(None, config=config)
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import MemorySaver
agent = create_agent(
model="gpt-4",
tools=[deploy_tool, send_email_tool],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"deploy_to_prod": {
"allowed_decisions": ["approve", "reject"],
"description": "🚨 PRODUCTION DEPLOYMENT requires approval"
},
"send_email": {
"description": "📧 Email draft ready for review"
},
},
),
],
checkpointer=MemorySaver(),
)
✅ Which tools require approval ✅ Allowed decision types per tool ✅ Custom interrupt descriptions ✅ Checkpointer implementation ✅ Interrupt handling logic
❌ The HITL protocol (approve/edit/reject structure) ❌ Skip checkpointer requirement ❌ Interrupt without saving state ❌ Have subagents interrupt without main checkpointer
# ❌ This will error
agent = create_deep_agent(
interrupt_on={"write_file": True}
)
# ✅ Must provide checkpointer
agent = create_deep_agent(
interrupt_on={"write_file": True},
checkpointer=MemorySaver()
)
# ❌ Can't resume without thread_id
agent.invoke({"messages": [...]})
agent.update_state(...) # Which thread?
# ✅ Use consistent thread_id
config = {"configurable": {"thread_id": "session-1"}}
agent.invoke({...}, config=config)
agent.update_state(config, ...)
# Interrupts don't happen mid-invoke()
# They happen between invoke() calls
# Step 1: invoke() -> interrupt occurs
result = agent.invoke({...}, config=config)
# Step 2: Check state for interrupts
state = agent.get_state(config)
if state.next: # Has interrupts
# Handle interrupts
# Step 3: Resume with decision
agent.update_state(config, {...})
result = agent.invoke(None, config=config)
# ❌ Edited args must match tool schema
agent.update_state(config, {
"messages": [Command(resume={
"decisions": [{
"type": "edit",
"args": {"wrong_param": "value"} # Tool doesn't have this param
}]
})]
})
# ✅ Use correct parameter names from tool schema