Human-in-the-Loop
Hive integrates Human-in-the-Loop (HITL) capabilities as a first-class citizen in the agent runtime. This allows developers to design workflows that pause for manual intervention, require code/test approvals, or escalate complex decisions to a human operator.
The HITL system is built around a request-response cycle using standardized approval types, ensuring compatibility across the CLI, TUI, and MCP-based interfaces.
Core Concepts
In Hive, HITL typically manifests in two ways:
- Approval Workflows: Specific steps (like LLM-generated tests) that require explicit user sign-off before proceeding.
- Runtime Pausing: Nodes that transition to a
pausedorescalatedstate, waiting for an external signal to resume.
Approval Actions
The ApprovalAction enum defines the four primary ways a user can interact with a pending request:
| Action | Description |
| :--- | :--- |
| APPROVE | Accepts the proposed item or state as-is. |
| MODIFY | Accepts the proposal but includes user-provided modifications (e.g., edited code). |
| REJECT | Declines the proposal and requires a reason. |
| SKIP | Defers the decision, leaving the state pending for later resolution. |
Interactive Approval CLI
For developers working locally, Hive provides an interactive CLI flow to review generated artifacts (such as tests or code changes).
from framework.testing.approval_cli import interactive_approval
from framework.testing.test_storage import TestStorage
# Initialize storage and fetch pending tests
storage = TestStorage(base_path="./tests")
pending_tests = storage.get_pending_tests(goal_id="research_task_1")
# Launch the interactive terminal UI
results = interactive_approval(
tests=pending_tests,
storage=storage
)
During this flow, users are presented with the proposed artifact and can trigger actions via keyboard shortcuts (e.g., [a] for approve, [e] for edit).
Programmatic and MCP Approvals
For headless environments or custom frontends, Hive supports batch processing of approvals via the BatchApprovalRequest. This is the primary interface used by the Model Context Protocol (MCP) server.
Data Models
ApprovalRequest
The base model for a single approval decision.
class ApprovalRequest(BaseModel):
test_id: str
action: ApprovalAction
modified_code: str | None = None # Required if action is MODIFY
reason: str | None = None # Required if action is REJECT
approved_by: str = "user"
BatchApprovalResult
The result returned after processing multiple requests, providing a summary of the execution quality.
# Summary example: "Processed 10 tests: 8 approved, 1 modified, 1 rejected, 0 skipped, 0 errors"
result = batch_approval(goal_id="task_id", requests=my_requests, storage=my_storage)
print(result.summary())
Integrating HITL in Agent Graphs
When building a custom agent using the AgentRuntime, you can define nodes that trigger a pause. The runtime monitors node exit_status values to manage the lifecycle of a human intervention.
Monitoring HITL States
The RunSummaryLog and NodeDetail models track whether a run requires human attention:
needs_attention: A boolean flag indicating the agent is stuck or requires a decision.attention_reasons: A list of strings explaining why the human is being looped in (e.g., "High cost threshold reached", "Safety guardrail triggered", "Manual approval required").exit_status: Look for statuses likepausedorescalatedin theNodeDetaillogs to identify precisely where the agent stopped.
TUI Visualization
The AdenTUI provides real-time visibility into HITL states. When a node enters an active or paused state, the GraphOverview widget updates the node's visual representation:
- Active Node: Highlighted in bold green.
- Paused/Escalated: Visible via the status bar and node detail indicators, allowing developers to see exactly which branch of the graph is awaiting input.
Validation Logic
The framework enforces strict validation on HITL responses. If a user attempts to MODIFY without providing new code, or REJECT without a reason, the validate_action() method will return a failure, preventing the agent from resuming with corrupted or incomplete state.
request = ApprovalRequest(test_id="123", action=ApprovalAction.MODIFY)
is_valid, error_msg = request.validate_action()
# is_valid will be False because modified_code is missing.