Agent SDK Human-in-the-Loop Interaction and Approval Guide

    Learn how to design a unified, non-blocking, and auditable human-in-the-loop mechanism for AI agent SDKs. This guide covers tool approvals, structured user questions, bidirectional messaging, configuration assembly, security, observability, timeouts, cancellation, and resumable execution.

    Agent SDK Human-in-the-Loop Interaction and Approval Guide

    During agent execution, a model does more than generate text. It may call tools, perform actions, and request authorization, additional information, or decisions from the user at critical points. Unlike a traditional conversational system, an agent behaves more like an executor with a bidirectional control flow: it can interrupt the current process at any time, request instructions from the user, and continue based on the response.

    For this reason, an agent SDK needs a unified, non-blocking, and auditable human-intervention mechanism. Approval requests, user questions, and information collection should not be implemented as separate systems, which can lead to inconsistent state management and higher maintenance costs.

    This guide presents an implementable design covering interaction goals, unified interaction handling, tool approvals, user questions, messaging protocols, configuration assembly, security, and observability.

    1. Design Goals and Core Principles

    The primary goal of a human-intervention mechanism is to provide a consistent human-agent interaction entry point during execution. It should support tool approvals, user questions, and additional information requests, ensuring that the agent receives human confirmation or guidance at important execution steps.

    The core principles are:

    1. Use a unified mechanism: All interaction types—including approvals, selections, and free-form input—should use the same interaction callback or event channel. The SDK should maintain consistent request IDs, state management, and timeout policies internally instead of relying on multiple parallel mechanisms.
    2. Keep execution non-blocking: The agent should not block the entire execution thread while waiting for a user response. Use asynchronous waiting, event-driven processing, or a state machine. “Waiting for user input” should be treated as a resumable state.
    3. Support cancellation and timeouts: Every interaction request should define timeout, cancellation, retry, and idempotency semantics. If the user does not respond, the executor should be able to degrade gracefully, terminate the operation, or route it to a human queue according to policy.
    4. Use structured data: Approval reasons, question options, and supplemental information should be transmitted in structured form to support frontend rendering, audit logging, and later analysis.
    5. Apply least privilege and maintain auditability: Tool approvals should work with authorization policies. The system should record who approved which operation and when, while retaining rejection reasons and correction suggestions.

    2. A Unified Interaction Mechanism Centered on Tool Approval Callbacks

    The key to a unified mechanism is to model approvals, selections, and user input as the same type of interaction request. When human intervention is required, the executor creates an interaction request and suspends the current step. A frontend or command-line client receives the request and presents it to the user. After the user submits a result, the executor resumes the appropriate state.

    Illustrative pseudocode:

    1. function request_interaction(type, payload):
    2. request_id = generate_id()
    3. state = WAITING_USER
    4. emit_event("interaction_request", {
    5. request_id: request_id,
    6. type: type,
    7. payload: payload,
    8. timeout_ms: payload.timeout_ms
    9. })
    10. return await_response(request_id, state)
    11. function on_interaction_result(result):
    12. validate(result.request_id)
    13. if result.type == "tool_approval":
    14. return handle_tool_approval(result)
    15. if result.type == "user_question":
    16. return handle_user_answer(result)
    17. if result.type == "info_supplement":
    18. return handle_info_supplement(result)

    The specific API names are not important here. The essential design is that all interactions use the same event channel, a shared request ID, a common state machine, and consistent timeout handling. Tool approval is only one interaction strategy; user questions and information requests should reuse the same request-response model.

    3. Tool Approval Workflows and Three Approval Strategies

    Tool approval is used to obtain user confirmation before the agent invokes a high-risk or high-impact tool. The SDK should support three approval strategies:

    • Approve execution: The user approves the tool call. The executor continues and records the approver, approval time, and a summary of the tool parameters.
    • Reject execution: The user rejects the tool call and provides a reason. The executor should return the reason to the agent so it can adjust its next steps.
    • Reject with corrective feedback: The user rejects the current call and provides a correction. The command-line client or frontend should receive both the complete reason and the suggested correction. The agent can then modify the parameters, select an alternative tool, or re-plan the task.

    A recommended approval workflow is:

    1. Before calling a tool, the executor creates an approval request containing the tool name, parameter summary, risk level, expected impact, and timeout.
    2. The frontend displays an approval card. The user chooses to approve, reject, or provide corrective feedback.
    3. The executor validates the request ID and current state to prevent duplicate approvals and replay.
    4. If approved, the executor runs the tool and records an audit event. If rejected, it adds the rejection reason to the agent context. If corrective feedback is provided, it adds both the reason and the suggestion.
    5. If the request times out, the executor terminates, degrades, or routes the operation to a human according to policy.

    Example approval result:

    1. {
    2. "request_id": "req-001",
    3. "decision": "feedback",
    4. "reason": "The parameter range is too broad. Please reduce the scope.",
    5. "suggestion": "Process only data within the current user's authorized scope.",
    6. "operator": "user-123",
    7. "timestamp": "2025-01-01T10:00:00Z"
    8. }

    Approval policies should be configurable. Low-risk tools can be approved automatically, medium-risk tools can be sampled for approval according to rules, and high-risk tools should always require human confirmation. Every approval result must be included in the execution trace for later review.

    4. Designing User Questions and Information Requests

    User questions allow the agent to request structured information when the available context is insufficient. Common formats include single-choice questions, multiple-choice questions, and free-form input.

    Avoid allowing the model to generate uncontrolled natural-language follow-up questions directly. Instead, constrain question generation with structured templates.

    For example, a prompt template can require one single-choice question and one multiple-choice question about the user’s preferred technical direction and commonly used tool categories. The caller provides the candidate options. A question object should generally include a question ID, prompt, type, options, required status, default value, and timeout.

    1. {
    2. "question_id": "q-01",
    3. "type": "single_choice",
    4. "prompt": "Select your preferred technical direction",
    5. "options": ["Direction A", "Direction B", "Direction C"],
    6. "required": true
    7. }

    Multiple-choice questions should support minimum and maximum selection counts. Free-form input should have length limits and undergo security filtering. After receiving an answer, the executor should verify that:

    • Selected values belong to the available options.
    • Required fields are present.
    • Selection counts satisfy the configured constraints.

    The validated, structured answer can then be added to the agent context. If the user cancels or the request times out, the executor should return that state explicitly rather than allowing the agent to guess.

    Information collection can be treated as a variant of free-form question answering. It is useful when configuration details, authorization information, or additional context are missing. The supplemental information should be associated with the original request to prevent context drift.

    5. Bidirectional Control-Flow Messaging Protocol

    Communication between the agent executor and the frontend should use a downstream push plus upstream submission model. The backend can push downstream messages to the frontend through SSE, while the frontend submits user actions through HTTP POST.

    A message envelope should include:

    • Message ID
    • Parent request ID
    • Message type
    • Timestamp
    • Payload
    • Status
    • Trace ID

    Common message types include:

    • Tool approval requests
    • User questions
    • Information requests
    • Approval results
    • User answers
    • Cancellation commands
    • Heartbeats
    • Errors

    The executor should maintain states such as:

    • Running
    • Waiting for approval
    • Waiting for a user answer
    • Resumed
    • Cancelled
    • Timed out
    • Failed

    Key design considerations include:

    • Idempotency: Process a repeated submission for the same request ID only once.
    • Ordering and correlation: Use the parent request ID to associate questions and answers with execution steps.
    • Reconnect and recovery: After reconnecting, the frontend should be able to retrieve incomplete requests by trace ID.
    • Backpressure and rate limiting: Prevent a large number of interaction requests from arriving simultaneously.
    • Clear error semantics: Distinguish user rejection, timeout, cancellation, and system errors.

    6. Configuration Assembly and Executor Initialization

    During executor initialization, agent configuration should be assembled into a consistent structure. Configuration may come from a database, configuration file, or configuration center. The assembler is responsible for loading default, environment, and user-specific configuration, then merging, validating, and freezing the result.

    A configuration object should include:

    • Agent name
    • Instructions
    • Available tools
    • Interaction policies
    • Approval rules
    • Timeout and retry limits
    • Observability settings

    The assembler should perform schema validation, verify that tools are on the allowlist, check that approval policies are valid, and ensure that timeout values fall within permitted ranges. It should then produce an immutable configuration object for the executor.

    1. config = load_defaults()
    2. config = merge(config, load_environment())
    3. config = merge(config, load_user_config())
    4. validate(config)
    5. freeze(config)

    Sensitive information, such as secrets, should not be stored in plaintext configuration. Use secure injection mechanisms instead. The frozen configuration should include a version number so that execution behavior can be traced over time.

    7. Security, Observability, and Best Practices

    From a security perspective, follow the principle of least privilege. Grant only the permissions required for the current step. Require a second confirmation for high-risk operations. Redact sensitive information from approval reasons and parameter summaries. Every interaction request should support timeouts and cancellation.

    Audit logs should record the request ID, operator, decision, reason, and trace ID.

    For observability, assign a trace ID to every interaction and record metrics such as:

    • User wait duration
    • Approval rate
    • Distribution of rejection reasons
    • Timeout rate
    • User cancellation rate

    These metrics can be connected to standard logging and monitoring systems to identify approval bottlenecks and abnormal tool invocation patterns.

    Implementation Checklist

    1. Route all interactions through a unified request-response channel instead of maintaining parallel mechanisms.
    2. Support approval, rejection, and corrective feedback for tool approvals.
    3. Use structured templates for user questions and validate options and required fields.
    4. Ensure that the messaging protocol supports idempotency, timeouts, cancellation, and reconnect recovery.
    5. Make the configuration assembler responsible for loading, merging, validating, and freezing configuration.
    6. Make the entire approval and question-answering process auditable, traceable, and capable of redacting sensitive data.
    7. Apply stricter approval rules and timeout policies to high-risk tools.

    With these design principles, an agent SDK can preserve execution efficiency while returning critical decision-making authority to humans. The result is a human-agent collaboration system that is confirmable, interruptible, resumable, and auditable.