HITL Router Node
Route tasks to specific human reviewers based on criteria like expertise, workload, or priority.
Overview
The HITL Router Node assigns review tasks to specific reviewers based on configurable routing rules. It enables:
- Expert routing - Send complex cases to specialized reviewers
- Workload balancing - Distribute tasks evenly across available reviewers
- Priority escalation - Route urgent tasks to senior reviewers
- Team assignment - Route by document type, customer, or region
- SLA management - Ensure high-priority tasks meet deadlines
Unlike Approval or Correction nodes (which define task structure), the Router focuses on assignment logic.
When to Use
Use a HITL Router Node when you need:
- Specialized expertise - Medical claims to medical reviewers, legal docs to attorneys
- Dynamic assignment - Route based on content, metadata, or real-time availability
- Workload balancing - Prevent reviewer overload by distributing evenly
- Escalation logic - Route to senior reviewers if automated confidence is low
- Multi-tier review - First-pass review by juniors, second-pass by seniors
For simple fixed assignment, configure reviewers directly in Approval/Correction nodes.
Configuration
Routing Rules
Define how tasks are assigned:
{
"routing_rules": [
{
"condition": "$.nodes.classify.output.category == 'medical'",
"reviewers": ["role:medical_reviewer"],
"priority": "high"
},
{
"condition": "$.nodes.classify.output.category == 'legal'",
"reviewers": ["role:legal_reviewer"],
"priority": "high"
},
{
"condition": "$.data.amount > 10000",
"reviewers": ["role:senior_reviewer"],
"priority": "urgent"
},
{
"condition": "default",
"reviewers": ["team:general_review"],
"priority": "normal"
}
]
}Rules are evaluated in order. First matching rule determines assignment.
Assignment Strategies
Control how reviewers are selected:
| Strategy | Description | Use Case |
|---|---|---|
| round_robin | Assign to reviewers in rotation | Equal distribution |
| load_balanced | Assign to reviewer with fewest pending tasks | Prevent overload |
| random | Random selection from eligible reviewers | Fair distribution without patterns |
| priority_based | Assign to highest-priority reviewer available | Expert routing |
| specific_user | Assign to named user | VIP customer or special case |
{
"assignment_strategy": "load_balanced",
"fallback_strategy": "round_robin"
}If no eligible reviewers for primary strategy, use fallback.
Reviewer Pools
Define pools of reviewers with metadata:
{
"reviewer_pools": {
"medical_experts": {
"members": ["user_123", "user_456", "user_789"],
"expertise": ["cardiology", "radiology", "oncology"],
"max_concurrent_tasks": 10
},
"legal_team": {
"members": ["user_abc", "user_def"],
"expertise": ["contracts", "compliance"],
"max_concurrent_tasks": 5
},
"general_review": {
"members": ["user_111", "user_222", "user_333", "user_444"],
"max_concurrent_tasks": 20
}
}
}Routing rules reference pools by name.
Priority Levels
Assign priority to tasks based on routing criteria:
| Priority | SLA | Notification | Use Case |
|---|---|---|---|
| urgent | 1 hour | Immediate SMS/email | System outages, VIP customers |
| high | 4 hours | Email + in-app | High-value transactions, compliance |
| normal | 24 hours | In-app only | Standard operations |
| low | 7 days | Batch email | Training data, non-critical review |
{
"priority_mapping": [
{
"condition": "$.data.customer_tier == 'vip'",
"priority": "urgent"
},
{
"condition": "$.nodes.extract.output.amount > 50000",
"priority": "high"
},
{
"condition": "default",
"priority": "normal"
}
]
}Routing Examples
Route by Document Type
{
"routing_rules": [
{
"condition": "$.nodes.classify.output.doc_type == 'invoice'",
"reviewers": ["team:accounts_payable"],
"assignment_strategy": "load_balanced"
},
{
"condition": "$.nodes.classify.output.doc_type == 'contract'",
"reviewers": ["team:legal"],
"assignment_strategy": "round_robin"
},
{
"condition": "$.nodes.classify.output.doc_type == 'medical_claim'",
"reviewers": ["pool:medical_experts"],
"assignment_strategy": "priority_based",
"priority": "high"
}
]
}Route by Confidence Score
Route low-confidence extractions to expert reviewers:
{
"routing_rules": [
{
"condition": "$.nodes.extract.output.confidence < 0.7",
"reviewers": ["role:expert_reviewer"],
"priority": "high",
"comment": "Low confidence extraction, requires expert review"
},
{
"condition": "$.nodes.extract.output.confidence >= 0.7 && $.nodes.extract.output.confidence < 0.9",
"reviewers": ["team:general_review"],
"priority": "normal"
},
{
"condition": "$.nodes.extract.output.confidence >= 0.9",
"reviewers": ["role:quality_assurance"],
"priority": "low",
"assignment_strategy": "random",
"sample_rate": 0.1
}
]
}The last rule samples 10% of high-confidence extractions for spot-checking.
Route by Customer Tier
{
"routing_rules": [
{
"condition": "$.data.customer.tier == 'enterprise'",
"reviewers": ["user_senior_account_manager"],
"assignment_strategy": "specific_user",
"priority": "urgent",
"sla_hours": 1
},
{
"condition": "$.data.customer.tier == 'business'",
"reviewers": ["team:account_managers"],
"assignment_strategy": "load_balanced",
"priority": "high",
"sla_hours": 4
},
{
"condition": "default",
"reviewers": ["team:support"],
"assignment_strategy": "round_robin",
"priority": "normal",
"sla_hours": 24
}
]
}Route by Region and Language
{
"routing_rules": [
{
"condition": "$.data.region == 'EMEA' && $.nodes.detect_language.output.language == 'de'",
"reviewers": ["team:emea_de"],
"priority": "normal"
},
{
"condition": "$.data.region == 'EMEA' && $.nodes.detect_language.output.language == 'fr'",
"reviewers": ["team:emea_fr"],
"priority": "normal"
},
{
"condition": "$.data.region == 'AMER'",
"reviewers": ["team:americas"],
"priority": "normal"
}
]
}Advanced Features
Cascading Routing
Route through multiple tiers:
{
"tier_1": {
"reviewers": ["team:junior_reviewers"],
"assignment_strategy": "load_balanced",
"timeout_hours": 24,
"on_timeout": "escalate_to_tier_2"
},
"tier_2": {
"reviewers": ["team:senior_reviewers"],
"assignment_strategy": "round_robin",
"timeout_hours": 12,
"on_timeout": "escalate_to_tier_3"
},
"tier_3": {
"reviewers": ["role:manager"],
"assignment_strategy": "specific_user",
"timeout_hours": 6,
"on_timeout": "alert_leadership"
}
}Tasks auto-escalate if not completed within SLA.
Reviewer Availability
Consider reviewer availability and working hours:
{
"availability_rules": {
"respect_working_hours": true,
"working_hours": {
"timezone": "America/New_York",
"start": "09:00",
"end": "17:00",
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"]
},
"out_of_hours_fallback": {
"reviewers": ["team:on_call"],
"priority": "urgent"
}
}
}Tasks assigned outside working hours route to on-call team.
Skill-Based Routing
Match reviewer expertise to document requirements:
{
"skill_matching": {
"required_skills": ["$.nodes.classify.output.required_expertise"],
"reviewer_skills": {
"user_123": ["cardiology", "radiology"],
"user_456": ["oncology", "pathology"],
"user_789": ["general_medicine"]
},
"fallback_if_no_match": {
"reviewers": ["role:generalist"],
"add_note": "No specialist available, assigned to generalist"
}
}
}Routes to reviewer with matching skill, falls back to generalist if none available.
Output
The HITL Router Node produces assignment metadata:
{
"routing_result": {
"assigned_reviewer_id": "user_123",
"assigned_reviewer_email": "jane.doe@company.com",
"assignment_strategy": "load_balanced",
"priority": "high",
"sla_deadline": "2026-03-19T18:30:00Z",
"routing_reason": "Medical expertise match: cardiology",
"selected_path_id": "assigned"
}
}Access via JSONPath:
$.nodes.router.output.routing_result.assigned_reviewer_id$.nodes.router.output.routing_result.priority
Workload Management
Capacity Limits
Prevent reviewer overload:
{
"capacity_limits": {
"user_123": {
"max_concurrent_tasks": 10,
"max_daily_tasks": 50
},
"team:general_review": {
"max_concurrent_tasks_per_member": 15,
"max_daily_tasks_per_member": 75
}
},
"overflow_action": {
"type": "queue",
"notify_manager": true
}
}If all reviewers at capacity, tasks queue and manager is notified.
Balancing Metrics
Track load balancing effectiveness:
| Metric | Description | Target |
|---|---|---|
| Task distribution variance | Evenness of task distribution | < 10% variance |
| Average wait time | Time from assignment to first view | < 30 minutes |
| SLA compliance | % tasks completed within SLA | > 95% |
| Reviewer utilization | % of capacity used | 70-90% |
View in OPERATE → Analytics → Reviewer Workload.
Notifications
Notify reviewers when tasks are assigned:
{
"notifications": {
"on_assignment": {
"email": true,
"in_app": true,
"sms": false
},
"urgent_assignments": {
"email": true,
"in_app": true,
"sms": true,
"phone_call": true
},
"approaching_sla": {
"hours_before_deadline": [2, 0.5],
"email": true,
"in_app": true
}
}
}Urgent tasks trigger SMS/call for immediate attention.
Best Practices
- Define clear routing rules - Use explicit conditions, avoid ambiguous logic
- Test routing logic - Verify assignments with test scenarios before production
- Monitor workload balance - Alert if variance exceeds threshold
- Set realistic SLAs - Match reviewer capacity and working hours
- Provide routing context - Add comments explaining why task was routed
- Handle edge cases - Always have default/fallback routing rule
- Respect availability - Don’t assign during off-hours unless urgent
- Track metrics - Monitor SLA compliance and distribution fairness
Routing logic runs synchronously at workflow execution time. Complex routing with many rules may add latency.
Integration with Review Systems
HITL Router integrates with external review systems:
{
"external_integration": {
"type": "webhook",
"endpoint": "https://review-system.company.com/api/tasks",
"headers": {
"Authorization": "Bearer {{gateway_token}}"
},
"payload": {
"task_id": "$.run_id",
"assigned_to": "$.nodes.router.output.routing_result.assigned_reviewer_email",
"priority": "$.nodes.router.output.routing_result.priority",
"data": "$.nodes.extract.output"
}
}
}Creates tasks in external systems with routing metadata.
API Access
Programmatically manage routing:
// Get routing stats
const stats = await trpc.routing.getStats.query({
time_range: 'last_24h'
});
// Override routing for specific task
await trpc.routing.override.mutate({
task_id: 'task_abc123',
new_reviewer_id: 'user_xyz',
reason: 'Original reviewer unavailable'
});
// Get reviewer workload
const workload = await trpc.routing.getReviewerWorkload.query({
reviewer_id: 'user_123'
});Related Nodes
- HITL Approval Node - Human approval gate
- HITL Correction Node - Data correction
- Guardrail Node - Automated routing based on quality