| title | Human-in-the-Loop (HITL) Workflows |
|---|---|
| description | Pause AI tool execution for user approval before risky operations like file deletion or API calls |
| keywords | hitl, human in the loop, tool confirmation, safety, approval workflow, user consent |
Since: v7.39.0 | Status: Stable | Availability: SDK
What it does: HITL pauses AI tool execution to request explicit user approval before performing risky operations like deleting files, modifying databases, or making expensive API calls.
Why use it: Prevent costly mistakes and give users control over potentially dangerous AI actions. Think of it as an "Are you sure?" dialog for AI assistant operations.
:::warning[Security Best Practice] Only use HITL for truly risky operations. Overusing confirmation prompts degrades user experience and can lead to "confirmation fatigue" where users approve actions without reading them. :::
Common use cases:
- File deletion or modification operations
- Database write/delete operations
- Expensive third-party API calls
- Irreversible actions (sending emails, posting to social media)
- Operations accessing sensitive data
import { NeuroLink } from "@juspay/neurolink";
const neurolink = new NeuroLink({
tools: [
{
name: "deleteFile", // (1)!
description: "Deletes a file from the filesystem", // (2)!
requiresConfirmation: true, // (3)!
execute: async (args) => {
// (4)!
// Your deletion logic
},
},
],
});
// When AI tries to use deleteFile:
// 1. Tool execution pauses
// 2. Returns USER_CONFIRMATION_REQUIRED error
// 3. Application shows confirmation dialog
// 4. On approval, tool executes with confirmation_received = true- Tool identifier used by the AI to invoke this function
- Describes tool purpose to the LLM for proper selection
- Triggers HITL checkpoint before execution
- Actual implementation only runs after user approval
HITL uses an event-based workflow where the SDK emits confirmation requests and your app responds with user decisions.
import { NeuroLink } from "@juspay/neurolink";
const neurolink = new NeuroLink({
hitl: {
enabled: true,
dangerousActions: ["delete", "remove", "drop", "truncate"],
timeout: 30000, // 30 seconds
},
});
// (1)! Listen for confirmation requests
neurolink.on("hitl:confirmation-request", async (event) => {
const {
confirmationId,
toolName,
arguments: args,
timeoutMs,
} = event.payload;
// (2)! Show your app's confirmation UI
const approved = await showConfirmationDialog({
action: toolName,
details: args,
message: `AI wants to ${toolName}. Allow?`,
timeoutMs,
});
// (3)! Send response back to NeuroLink
neurolink.emit("hitl:confirmation-response", {
type: "hitl:confirmation-response",
payload: {
confirmationId, // (4)! Must match the request
approved, // (5)! User decision
reason: approved ? undefined : "User denied permission",
metadata: {
timestamp: new Date().toISOString(),
responseTime: Date.now(), // Track response speed
},
},
});
});
// (6)! Handle confirmation timeouts
neurolink.on("hitl:timeout", (event) => {
console.warn(`Confirmation timed out for ${event.payload.toolName}`);
});- Event-based confirmation workflow - NeuroLink emits requests, your app handles them
- Show confirmation UI with tool details and countdown timer
- Respond using event emitter with confirmation ID
- Confirmation ID links the response to the specific request
- Approval decision determines if tool executes
- Optional: Handle cases where user doesn't respond in time
| Option | Type | Default | Required | Description |
|---|---|---|---|---|
requiresConfirmation |
boolean |
false |
No | Mark tool as requiring user approval |
const riskyTool = {
name: "sendEmail",
description: "Sends an email to a recipient",
requiresConfirmation: true, // Enable HITL
parameters: {
/* ... */
},
execute: async (args) => {
/* ... */
},
};- AI requests tool execution → Tool executor checks if tool requires confirmation
- Confirmation required? → Returns
USER_CONFIRMATION_REQUIREDerror to LLM - LLM asks user → "I need to [action]. Is that okay?"
- User responds:
- Approve → UI sets
confirmation_received = trueand retries tool execution - Deny → UI sends "User cancelled" message back to LLM
- Approve → UI sets
- Tool executes → Permission flag immediately resets to
false
- One-time permissions: Each approval works for exactly one action
- No reuse: AI cannot reuse old permissions for new actions
- Automatic reset: Permission flag clears immediately after use
- Fail-safe: Defaults to requiring permission when in doubt
Confirmation Request Event (hitl:confirmation-request):
neurolink.on("hitl:confirmation-request", (event) => {
event.payload: {
confirmationId: string; // Unique ID for this request
toolName: string; // Tool requiring confirmation
arguments: unknown; // Tool parameters for review
actionType: string; // Human-readable description
timeoutMs: number; // Milliseconds until timeout
allowModification: boolean; // Can user edit arguments?
metadata: { ... } // Session/user context
}
});Confirmation Response (emit from your app):
neurolink.emit("hitl:confirmation-response", {
type: "hitl:confirmation-response",
payload: {
confirmationId: string; // Must match request
approved: boolean; // User decision
reason?: string; // Rejection reason
modifiedArguments?: unknown; // User-edited args
metadata: {
timestamp: string;
responseTime: number;
}
}
});Timeout Event (hitl:timeout):
neurolink.on("hitl:timeout", (event) => {
event.payload: {
confirmationId: string;
toolName: string;
timeout: number;
}
});See human-in-the-loop.md for complete technical documentation.
Cause: Tool not marked with requiresConfirmation: true
Solution:
// Add confirmation flag to tool definition
const tool = {
name: "deleteTool",
requiresConfirmation: true, // (1)!
// ...
};- Add this boolean flag to any tool that performs risky operations
Cause: Confirmation responses not being sent or sent with wrong confirmationId
Solution:
// Always respond to confirmation requests with matching ID
neurolink.on("hitl:confirmation-request", async (event) => {
const { confirmationId } = event.payload; // (1)!
const approved = await showConfirmationDialog(event.payload);
// (2)! Send response with EXACT confirmationId from request
neurolink.emit("hitl:confirmation-response", {
type: "hitl:confirmation-response",
payload: {
confirmationId, // (3)! Must match request exactly
approved,
metadata: {
timestamp: new Date().toISOString(),
responseTime: Date.now(),
},
},
});
});- Extract confirmation ID from the request event
- Always respond to every confirmation request
- Critical: Use the same confirmationId from the request
Cause: Not listening to hitl:confirmation-request event
Solution:
// Set up event listener BEFORE making AI requests
neurolink.on("hitl:confirmation-request", async (event) => {
// (1)! Show your confirmation UI
await handleConfirmationPrompt(event);
});
// (2)! Then make AI requests - confirmations will now work
const result = await neurolink.generate({
input: { text: "Delete all temporary files" },
});- Register the event handler early in your application startup
- All subsequent tool executions will trigger confirmations when needed
:::tip[Production Recommendation] Store user confirmation preferences to avoid repeated prompts for the same action type. For example, if a user approves "delete temporary files" once, cache that preference for similar low-risk deletions in the same session. :::
- Mark tools conservatively - If an operation could cause problems, require confirmation
- Clear prompts - Ensure users understand exactly what will happen
- Test confirmation flow - Verify it works smoothly in your UI
- Log approvals - Keep audit trail of user decisions
- Handle denials gracefully - Allow users to try alternative approaches
✅ Do require confirmation:
- File deletions
- Database writes/deletes
- Sending emails or messages
- Making purchases or payments
- Modifying production systems
❌ Don't require confirmation:
- Read-only operations
- Answering questions
- Generating content
- Searching/fetching data
- Guardrails Middleware - Content filtering and safety checks
- Custom Tools - Building your own tools with HITL
- Middleware Architecture - Advanced request interception
If upgrading from versions before v7.39.0:
- Review all existing tools for risk assessment
- Add
requiresConfirmation: trueto risky tools - Implement confirmation dialog in your UI
- Test with low-risk tools first
- Roll out to production gradually
For comprehensive technical documentation, diagrams, and security details, see the complete HITL guide.