Skip to main content

Task Agent

Task automation with human approval gates.

Difficulty: Intermediate

What You'll Learn

  • LangGraph interrupt() for human-in-the-loop
  • Resume from checkpoint after approval
  • Multi-step workflows
  • Durable execution

Workflow

plan_task -> await_approval --(approved)--> execute_task -> END
|
+--(rejected)--> revise_plan --+
|
+------------------------------+

Setup

agentvisor template create langgraph/task-agent
cd task-agent
docker compose up -d
agentvisor serve .

Test It

Approval Flow

THREAD=$(curl -sX POST http://localhost:8090/threads | jq -r '.thread_id')

# Step 1: Submit task (returns interrupted)
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "Send an email to the team about the meeting"}]}}'

# Step 2: Approve
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "approved"}]}}'

Rejection Flow

# Reject with feedback
curl -sX POST "http://localhost:8090/threads/$THREAD/runs?wait=60s" \
-H "Content-Type: application/json" \
-d '{"input": {"messages": [{"role": "user", "content": "rejected: make it more formal"}]}}'

Approval Commands

CommandAction
approved, yes, okExecute the plan
rejected: <feedback>Revise with feedback
rejected, noRevise with generic feedback

Key Code

Interrupt for Approval

from langgraph.types import interrupt

def await_approval(state):
interrupt({
"status": "awaiting_approval",
"plan": state.get("plan"),
"message": "Reply 'approved' or 'rejected: <feedback>'"
})
return {}

Conditional Routing

def check_approval(state) -> Literal["execute", "revise", "end"]:
user_response = get_last_user_message(state)
is_approved, feedback = parse_approval(user_response)

if is_approved:
return "execute"
if state.get("approval_attempts", 0) >= 3:
return "end"
return "revise"

Durable Execution

The workflow is durable:

  • State persisted in Temporal
  • Server can restart while awaiting approval
  • Resume continues exactly where it left off

Next Steps

  • MCP Agent: Dynamic tool loading with MCP integration